Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I automatically add labels to input fields?

I'm working on a bigger project with AngularJS. Therefore, I want to make the work for a single form as easy as possible. As we're also using bootstrap, the code for a single input field in a form is quite verbose, maybe like

<div class="control-group">
  <label class="control-label" for="inputEmail">Email</label>
  <div class="controls">
    <input type="text" id="inputEmail" placeholder="Email">
  </div>
</div>

If I could write a single tag like

<custom-input 
  label="Email" 
  name="inputEmail" 
  placeholder="Email" 
  type="text" 
  ... >
</custom-input>

instead, this would help to keep the code clean and the work simple.

To achive this, I'm working on a custom AngularJS directive. My directive currently uses a template similar to the bootstrap example from above, automatically assigning the label to the input-tag. Also, the directive's compiler function moves all attributes from the custom-input tag to the real input-tag in order to make it easy to customize the custom-input tag.

app.directive('customInput', function() {
    return {
      require: 'ngModel',
      restrict: 'E',
      template: '<div>' + 
                    '<label for="{{ name }}">the label</label>' +
                    '<input id="{{ name }}" ng-model="ngModel" />' +
                '</div>',
      scope: {
              ngModel: '=',
              name: '@name',
          },
      replace: true,
      compile: function (tElement, tAttrs, transclude) {
            var tInput = tElement.find('input');

            // Move the attributed given to 'custom-input'
            // to the real input field
            angular.forEach(tAttrs, function(value, key) {
                if (key.charAt(0) == '$')
                    return;
                tInput.attr(key, value);
                tInput.parent().removeAttr(key);
            });

            return;
        },
    };
});

On Stack Overflow, there are many questions regarding the creation of custom input fields, but they are concerned with the data binding, custom formatting or binding to ng-repeat.

My approach however has a different issue: while the data binding works correctly, Angular's integrated form validation module get confused when the input field is 'required'. For some reason, validation doesn't recognize the new input field and instead keeps the form invalid because of some dead reference, which has an empty value. Please see the minimal example.

Where does the dead reference come from? How can I update the validation-module's references? Is there a better way to achieve my overall goal?

like image 567
Nils Wilhelm Avatar asked Jun 14 '13 09:06

Nils Wilhelm


People also ask

How do you put a label inside an input field?

There are two ways to pair a label and an input. One is by wrapping the input in a label (implicit), and the other is by adding a for attribute to the label and an id to the input (explicit). Think of an implicit label as hugging an input, and an explicit label as standing next to an input and holding its hand.

How do you put a label next to input?

We specify the margin-bottom of our <div> element. Then, we set the display of the <label> element to "inline-block" and give a fixed width. After that, set the text-align property to "right", and the labels will be aligned with the inputs on the right side.

How do you put a label and input on the same line in HTML?

Using table cell attribute in display property: Make a label inside a div and give the display property. To make the input element and span as equally placed use table-cell attribute in those tags. This attribute makes the element behaves a td element.


1 Answers

  1. As a boolean attribute, there is a corresponding required property that is still true on your div even if the attribute is moved.
  2. The required attribute isn't getting moved, it must be getting skipped because there is no value. I don't know how to even add it to an element using javascript without a value, but using the form required="required" fixes that
  3. Using transclude=true will use a copy of your element after the compile phase when you moved attributes, I think this keeps the required property from being set
  4. You have to assign a higher priority for some reason, maybe because of ng-model, which is not removed from your div because the name in tattrs is ngModel (although removing from the div doesn't remove the need for priority)

http://plnkr.co/edit/5bg8ewYSAr2ka9rH1pfE?p=preview

All I did was change the required attribute to be required="required" and add these two lines to the directive declaration:

  transclude: true,
  priority: 10,

I put ng-transclude on the template label by the way so the contents of your element will go in the label and you don't have to have an attribute for that.

like image 120
Jason Goemaat Avatar answered Sep 20 '22 16:09

Jason Goemaat