Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

label for select #243

Closed
MaximBalaganskiy opened this issue Aug 30, 2016 · 15 comments
Closed

label for select #243

MaximBalaganskiy opened this issue Aug 30, 2016 · 15 comments

Comments

@MaximBalaganskiy
Copy link
Collaborator

Would be nice to have labels for dropdowns (selects). I've created a custom attribute for my project which works quite well, but I'm not qualified enough to submit a proper PR.

Here is the code:

// md-select-label.ts
import * as au from "aurelia";
import "./md-select-label.css!";

@au.noView
@au.autoinject
export class MdSelectLabelCustomAttribute {
    constructor(private element: Element) {
    }

    value: string;

    attached() {
        let input = $(this.element).prevAll("input.select-dropdown");
        let wrapper = $(this.element).parent(".select-wrapper");
        let div = $("<div class='input-field'></div>");
        let va = this.element.attributes.getNamedItem("validate");
        if (va)
            div.attr(va.name, va.value);
        wrapper.wrap(div);
        $(`<label>${this.value}</label>`).insertAfter(wrapper);
    }
}
// md-select-label.scss
.select-wrapper {

    input {
        // make input fit in div
        display: inline-block !important;
        // fix validation border thickness
        border-bottom: 1px solid #4CAF50;

        &.invalid {
            border-bottom: 1px solid #F44336;
        }
    }


    + label {
        width: 100%;
    }
    // position validation label
    + label:after {
        display: block;
        content: "";
        position: absolute;
        top: 60px;
        opacity: 0;
        transition: .2s opacity ease-out, .2s color ease-out;
        transform: translateY(0) !important;
    }
    // set validation text
    &.invalid {
        + label:after {
            content: attr(data-error);
            color: #F44336;
            opacity: 1;
        }
    }
}

Obviously, CSS colors will have to be set in the md-colors element as well

@MaximBalaganskiy
Copy link
Collaborator Author

MaximBalaganskiy commented Aug 31, 2016

Just tested the code in Edge and it does not work correctly - for some reason custom attribute's attached is called before the md-select.attached. Executing the jQuery manipulation through taskQueue fixes that

@Thanood
Copy link
Collaborator

Thanood commented Aug 31, 2016

Stupid question, maybe..

import * as au from "aurelia";

Is that new? 😄

How is it used? Like this?

    <select md-select md-select-label="My select label" value.two-way="selectedValue">
      <option value="" disabled selected>select an item</option>
      <option value="item1">item 1</option>
      <option value="item2">item 2</option>
      <option value="item3">item 3</option>
      <option value="item4">item 4</option>
    </select>

@MaximBalaganskiy
Copy link
Collaborator Author

Yep. The usage is exactly like this.
Import * is what I use to avoid import-hell :)
Aurelia is my module which just reexports all the needed stuff

On 31 Aug 2016 9:23 PM, "Daniel Bendel" [email protected] wrote:

Stupid question, maybe..

import * as au from "aurelia";

Is that new? 😄

How is it used? Like this?

<select md-select md-select-label="My select label" value.two-way="selectedValue">
  <option value="" disabled selected>select an item</option>
  <option value="item1">item 1</option>
  <option value="item2">item 2</option>
  <option value="item3">item 3</option>
  <option value="item4">item 4</option>
</select>


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#243 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADimvE-oafPx1BcIBUZMeulZIdJzwf6Jks5qlWQkgaJpZM4JxF-o
.

@Thanood
Copy link
Collaborator

Thanood commented Aug 31, 2016

Ah, thanks for clarifying this.
Regarding attach() load order, I guess it's random or depends on the order in which the browser reads attributes. I've had a similar problem with md-sidenav (trigger button loaded before sidenav). I could solve this with a promise - here and here

I think I can repeat this with your custom attribute as both attributes share the same element.

@MaximBalaganskiy
Copy link
Collaborator Author

I think it would be better to implement it on the original md-select. This
way you won't have to deal with attribute processing order and it will be
more solid

On 31 Aug 2016 9:35 PM, "Daniel Bendel" [email protected] wrote:

Ah, thanks for clarifying this.
Regarding attach() load order, I guess it's random or depends on the
order in which the browser reads attributes. I've had a similar problem
with md-sidenav (trigger button loaded before sidenav). I could solve
this with a promise - here
https://github.com/aurelia-ui-toolkits/aurelia-materialize-bridge/blob/master/src/sidenav/sidenav-collapse.js#L18
and here
https://github.com/aurelia-ui-toolkits/aurelia-materialize-bridge/blob/master/src/sidenav/sidenav.js#L23-L25

I think I can repeat this with your custom attribute.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#243 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADimvEjGCMNSLmbfZ79EonrducgPaJSBks5qlWcIgaJpZM4JxF-o
.

@Thanood
Copy link
Collaborator

Thanood commented Aug 31, 2016

Yes, I think you're right, thanks.
I'll give it a try.

@Thanood
Copy link
Collaborator

Thanood commented Aug 31, 2016

I'm a bit concerned about the css import:
import "./md-select-label.css!";

This will only work in JSPM this way and I'm not sure how to compensate for this. Any ideas?
md-colors? Although that's becoming more and more an "md-styles". 😄

@MaximBalaganskiy
Copy link
Collaborator Author

Arent you doing this for md-input?

You can include style tag in HTML I guess.

On 1 Sep 2016 3:36 AM, "Daniel Bendel" [email protected] wrote:

I'm a bit concerned about the css import:
import "./md-select-label.css!";

This will only work in JSPM this way and I'm not sure how to compensate
for this. Any ideas?


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#243 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADimvD60FRh0Q5wzgtFWO9hX2Wh_UeGLks5qlbuGgaJpZM4JxF-o
.

@Thanood
Copy link
Collaborator

Thanood commented Aug 31, 2016

md-input is a custom element which means it has a template. <require from="..."> works across all module systems.
I've asked for feedback on this here but no answer yet.

I guess until the above is solved we can go with md-colors. I just hope everybody uses that. 😄

@Thanood
Copy link
Collaborator

Thanood commented Sep 1, 2016

I've set the color to accent. What do you think? It usually implies "active" so I'm not sure..

image

@MaximBalaganskiy
Copy link
Collaborator Author

Will it always be active or only when you expand the list?

On 2 Sep 2016 4:18 AM, "Daniel Bendel" [email protected] wrote:

Set the color to accent. What do you think? It usually implies "active" so
I'm not sure..

[image: image]
https://cloud.githubusercontent.com/assets/677826/18179092/3ed521dc-7081-11e6-87a7-9fa900ebe6ba.png


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#243 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADimvGOfJC910e1SRjkH9ANdQdkGy0Bhks5qlxb-gaJpZM4JxF-o
.

@MaximBalaganskiy
Copy link
Collaborator Author

Also, validation won't work on selects as is because it only recognises MD-IMPUT element at the moment.

@Ullfis
Copy link
Contributor

Ullfis commented Sep 2, 2016

Try this one for validation 😄

export class MaterializeFormValidationRenderer {

  className = 'md-input-validation';
  classNameFirst = 'md-input-validation-first';

  render(instruction) {
    for (let { error, elements } of instruction.unrender) {
      for (let element of elements) {
        this.remove(element, error);
      }
    }
    for (let { error, elements } of instruction.render) {
      for (let element of elements) {
        this.add(element, error);
      }
    }
  }

  add(element, error) {
    switch (element.tagName) {
    case 'MD-INPUT': {
      let input = element.querySelector('input');
      let label = element.querySelector('label');
      if (input) {
        input.classList.remove('valid');
        input.classList.add('invalid');
        error.target = input;
      }
      if (label) {
        label.removeAttribute('data-error');
      }

      let message = document.createElement('div');
      message.id = `md-input-validation-${error.id}`;
      message.textContent = error.message;
      message.className = this.className;
      if (!element.querySelector('.' + this.className)) {
        message.className += ' ' + this.classNameFirst;
      }
      message.style.opacity = 0;
      element.appendChild(message, element.nextSibling);
      window.getComputedStyle(message).opacity;
      message.style.opacity = 1;
      break;
    }

    case 'SELECT': {
      const selectWrapper = element.closest('.select-wrapper');
      if (!selectWrapper) {
        return;
      }
      let input = selectWrapper.querySelector('input');
      if (input) {
        input.classList.remove('valid');
        input.classList.add('invalid');
        error.target = input;
      }

      let message = document.createElement('div');
      message.id = `md-input-validation-${error.id}`;
      message.textContent = error.message;
      message.className = this.className;
      if (!selectWrapper.querySelector('.' + this.className)) {
        message.className += ' ' + this.classNameFirst;
      }
      // Make the element fully transparent.
      message.style.opacity = 0;
      // message.style.color = color;
      selectWrapper.appendChild(message, selectWrapper.nextSibling);

      // Make sure the initial state is applied.
      window.getComputedStyle(message).opacity;
      // Fade it in.
      message.style.opacity = 1;
      break;
    }

    default: break;
    }
  }

  remove(element, error) {
    switch (element.tagName) {
    case 'MD-INPUT': {
      let message = element.querySelector(`#md-input-validation-${error.id}`);
      if (message) {
        element.removeChild(message);
      }

      let input = element.querySelector('input');
      if (input && element.querySelectorAll('.' + this.className).length === 0) {
        input.classList.remove('invalid');
        input.classList.add('valid');
      }
      break;
    }

    case 'SELECT': {
      const selectWrapper = element.closest('.select-wrapper');
      if (!selectWrapper) {
        return;
      }

      let message = selectWrapper.querySelector(`#md-input-validation-${error.id}`);
      if (message) {
        selectWrapper.removeChild(message);
      }

      let input = selectWrapper.querySelector('input');
      if (input && selectWrapper.querySelectorAll('.' + this.className).length === 0) {
        input.classList.remove('invalid');
        input.classList.add('valid');
      }
      break;
    }

    default: break;
    }
  }

}

Edit style-hack: added color to border bottom on input

add:

input.style.borderBottomColor = '#f44336';

remove:

input.style.borderBottomColor = null;

hmmf.. forgot to add md-colors where the style already was implemented

@MaximBalaganskiy
Copy link
Collaborator Author

MaximBalaganskiy commented Sep 2, 2016

If you look at the commits for this issue, they are adding a label to the control similar to a regular input field - wrapping it with div.input-field and adding a label below. With a little CSS fix (which is already in the repo) you can just assign data-error attribute on a label and set an invalid class. Here is the chunk of my implementation

            case 'SELECT': {
                let errorMessage = error.message || 'error';
                let input = element.parentElement.querySelector('input.select-dropdown');
                if (input) {
                    input.classList.remove('valid');
                    input.classList.add('invalid');
                    input.parentElement.classList.remove('valid');
                    input.parentElement.classList.add('invalid');

                    // focus target
                    (<any>error).target = input;

                    let label = element.parentElement.parentElement.querySelector('label');
                    if (label) {
                        // get error message from label
                        let msg = label.getAttribute('data-error');
                        if (!msg) {
                            // error message not set? add
                            label.setAttribute('data-error', errorMessage);
                        } else {
                            // set label message into error object
                            error.message = msg;
                        }
                    }
                }
                break;
            }

@Thanood
Copy link
Collaborator

Thanood commented Sep 18, 2016

Select label is in. 😃

@Thanood Thanood closed this as completed Sep 18, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants