1

I'm trying to create a custom form component which I can use ng-model to bind with. I've found loads of tutorials on how to do this with directives, but I can't seem to figure out how to do it with components as you can't have link functions with components, and trying to pass in the ngModel dependency to the controller results in this error:

Error: [$injector:unpr] Unknown provider: $ngModelProvider <- $ngModel

I've also seen this and tried this:

bindings: {
    value: "=ngModel"
}

I tried that, and then setting value in the controller for two way binding, but it doesn't seem to work.

2 Answers 2

1

This is a common misunderstanding with Components in Angular. Components should not modify data outside of their own scope. So, if you want to do this, you really should use a Directive.

Here is a quote from the documentation :

Components only control their own View and Data: Components should never modify any data or DOM that is out of their own scope. Normally, in Angular it is possible to modify data anywhere in the application through scope inheritance and watches. This is practical, but can also lead to problems when it is not clear which part of the application is responsible for modifying the data. That is why component directives use an isolate scope, so a whole class of scope manipulation is not possible.

Sign up to request clarification or add additional context in comments.

4 Comments

Interesting. So are you saying components should never use ngModel for outputting results? I don't see that as being much different then a 2-way binding, which is allowed. (although yes 2 way binding should also be used sparingly)
Well, I am quoting the docs. But, it is true that you can modify an an object using two way binding in a Component. But, you can't replace the object. And, the docs seem to imply that this was not the intended way to use components. Plus, if you really want to do that, just use a directive and you know exactly what you are getting.
So when creating form elements, it's not possible to make them as components, and they must be created as plain directives? I feel like that's kind of the point of components is to be able to create elements "that [are] similar to ... Web Components." And as such, it shouldn't be necessary to create directives to provide an interface to the form element's data. Components should be able to export their data in some way. Oh well...
In principle I agree with the quote. An exemple, a component <input-text ng-model="vm.value"></input-text> can be implemented to avoid redundant html code, validation message and much more. It can still be used with other ng directive which allows us to have simple validation implementation.
1

I think the angular-recommended way of doing callbacks (like ngclick for example) is to use the method binding type: &

Here is a plunkr example: https://plnkr.co/edit/nySL4OoMpJPkGXX8j78U?p=preview

Note this part, the method binding type is defines, and the internalChange function executes whatever angular expression is provided by the parent/caller.

  bindings: {
      valueChanged: '&?'
  }, 
  controller: function() {
      this.$onInit = function() {
          this.value = 'initial value';
      };
      this.internalChange = function() {
          if (this.valueChanged) {
              this.valueChanged({ $value: this.value} );
          }
      };  
  } 

And then here are 2 ways of many to use the expressions, note $value as defined by the component.

<my-comp data-value-changed="$ctrl.someFunction($value)"></my-comp> <br 
<my-comp data-value-changed="$ctrl.someProperty = 'Bla: ' + $value"></my-comp> 

I tried to set it up to show a variety of things.

  1. The method binding takes an angular expression. I have 2 examples, one calling a function on the parent controller, the other setting a property

  2. This expression is executed with the scope of the parent/caller (ie: has access to parent controller properties, functions etc...)

  3. The component is the one who invokes it by executing the binding name as a function

  4. The component can provide a map of key/value, where the key is a named property that can be used by the caller ($value in my example)

This is a good solution so long as you are OK with the component doing "push" updates to the parent. If for example you only wanted to fetch the data from the component at a specific time (possibly due to time or memory constraints), than there are many other different solutions for that problem.

Hope this helps!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.