5

I'm making a custom auto-complete directive that uses an <input> within itself, but I'm having a bit trouble figuring out how to pass the 'required' attribute down, other attributes that have values I can see but 'required' appears to be blank whether it is set or not. The first part of my return statement below:

return {
            restrict: 'E',
            template: tpl,
            replace: true,
            scope: {
                suggestionsPath: '=autoComplete',
                method: '@method',
                term: '@term',
                required: '@required',
                ngModel: "="
            }...

thanks!

kreek
  • 8,774
  • 8
  • 44
  • 69
  • You could try `ng-required` instead, and `ngRequired` in your directive's scope. – jpmorin Oct 15 '13 at 00:24
  • 2
    You could also look at what is inside the `attrs.required ` attribute in your link function and see if there is something. – jpmorin Oct 15 '13 at 00:27
  • 1
    Is there a reason you need an isolate scope for this? It may seem simpler but it often isn't. I'd suggest a different taking a requirement on the "ngModelController" and using "attrs" and $scope.$watch if you need dynamic binding. Let me know if you want a more complete solution, if you post a jsFiddle or something I'll try to help. – Chris Nicola Oct 15 '13 at 04:14
  • @ChrisNicola hey thanks for the response. I'm using isolate scope because the angular docs said that was best for reusable components, of course the docs may be wrong :) I'm trying to design the auto-complete directive as an 'extended' input directive so it would need to function as much as possible like an input, i.e. marking it as required and having it included in the validation routine. – kreek Oct 15 '13 at 17:51
  • If you want to extend an input directive then I highly recommend using ngModelController. I'll post an answer with the basics and we can go back and forth. I don't know exactly what youre directive needs to do so it may be incomplete. – Chris Nicola Oct 15 '13 at 21:33

3 Answers3

4

I've built a few extensions to inputs and the best (arguably) only way to extend existing ngModel bindings is using the ngModelController in your directive. You can require another directive's controller by using the "require" property. The documentation for ngModelController is here

This will allow you to get/set the model values as well as extend or replace the validation behavior as needed. Because you are now probably extending in combination AngularJS input directives you will also probably want to look at the input directives inside AngularJS for examples of how this work. They also can work in tangent with the ngFormController as a parent for the whole form. This took me a while to grasp so be patient but it is by far the best way to do this.

I would avoid isolate scopes here, they can be tricky, don't always play well with other directives (so typically only use it on new elements or things where only one directive will exists on it's own). I would design something like this:

return {
        restrict: 'E',
        template: tpl,
        replace: true,
        require: 'ngModel',
        link: function(scope, element, attrs, ngModelController) {
           // Use attrs to access values for attributes you have set on the lement
           // Use ngModelController to access the model value and add validation, parsing and formatting
           // If you have an attribute that takes an expression you can use the attrs value along with $scope.$watch to check for changes and evaluate it or the $parse service if you just want to evaluate it.
        }

I recommend getting as familiar as you can with directive design as custom inputs can get pretty tricky depending on what they do (we have built custom inputs that add +/- buttons as well as ones that format numbers as percentages, currencies or just numbers with commas while you type into them). Aside from the ngModelController docs these are useful to review:

Chris Nicola
  • 14,384
  • 6
  • 47
  • 61
2

Required is a bit of a funny attribute by itself (see here Setting an attribute named "required" and any value, with JQuery, doesn't work). You will likely have a lot of trouble passing any sort of value through on this as its effect is determined by whether it is present, not by its value. Different browsers will treat it differently and may rewrite the value.

You will also have trouble because both required and ngModel are directives that will be compiled on your element if they are provided. required will talk to ngModel and you will need to implement ngModel properly if you want things to work.

A simpler option is to rename required and ngModel to other names. e.g. myRequired and myNgModel. You can then bind ng-model directly to scope.myNgModel and bind an ng-required to myRequired.

Community
  • 1
  • 1
Andyrooger
  • 6,748
  • 1
  • 43
  • 44
2

I know this is an old question, but for others who come looking (which is how I ended up here):

you can pass the required tag to the directive to be read as a boolean, and then use that value in ng-required.

return {
    restrict: 'E',
    template: tpl,
    replace: true,
    scope {
        required:'@'
    }

Then in your directive template you would use it as

<input type="text" ng-required="required" />

Either the attribute 'required' is found and is then set to true in the directive, or the attribute is not found which will be interpreted by ng-required as a false value

rthill
  • 143
  • 1
  • 7
  • Just what I was looking for. Then in your html you can add 'required' or leave it out and will reflect on the directive. – Sagi Nov 11 '17 at 11:47