Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs: 2 way binding not working in included template

Tags:

angularjs

I think I'm missing something simple (and important) here. I'm using an included template that contains an input that's mapped to some value:

<div ng-controller="Ctrl">
    <div ng-include src="'template.html'"></div>
</div>

<!-- template -->
<script type="text/ng-template" id="template.html">
    <input ng-model="testvalue" />
</script>

Controller:

function Ctrl($scope) {    
   $scope.testvalue= "initial value";
}​

Alerting the value of $scope.testvalue always shows the initial value, not the updated value (when you type in the input). Help me Obi-Wan. You're our only hope.

Fiddle: http://jsfiddle.net/h5aac/

like image 789
Caleb Avatar asked Dec 12 '12 20:12

Caleb


People also ask

Does AngularJS support two way binding?

AngularJS creates a two way data-binding between the select element and the $ctrl.

How does two way data binding work in Angular?

The two-way data binding in Angular is used to display information to the end user and allows the end user to make changes to the underlying data using the UI. This makes a two-way connection between the view (the template) and the component class. This is similar to the two-way binding in WPF.

How to bind value in AngularJS?

The ng-bind Directive in AngularJS is used to bind/replace the text content of any particular HTML element with the value that is entered in the given expression. The value of specified HTML content updates whenever the value of the expression changes in the ng-bind directive.

What is one-way and two way data binding in Angular?

Difference between One-way & Two-way Binding This means that the flow of code is from ts file to Html file as well as from Html file to ts file. In order to achieve one-way binding, we used the property binding concept in Angular. In order to achieve a two-way binding, we will use ngModel or banana in a box syntax.


2 Answers

This is the all too common of binding to a primitive instead of an object. The value of the string gets passed around and not a reference to an object. If you use an object instead of a primitive, it works fine. Something like this in your scope.

$scope.foo = {testvalue: "initial value"};

See http://jsfiddle.net/h5aac/2/

Also:

Using `ng-model` within a transcluded directive in AngularJS

binding issue when a directive in a ngRepeat

AngularJS - updating scope value with asynchronous response

I'm sure there are more...

like image 143
dnc253 Avatar answered Sep 21 '22 08:09

dnc253


An alternative to referencing an object property in the parent scope is to use $parent to access the primitive in the parent scope:

<input ng-model="$parent.testvalue" />

ng-include creates a child scope. That scope prototypically inherits from Ctrl's parent scope. Here's how the 3 variations work:

  • $parent.testvalue ties the model to the property in the parent scope
  • testvalue by itself ties the model to a new property that will be created on the child scope. This property "shadows/hides" the parent scope property by the same name.
  • foo.testvalue (e.g., see @dnc253's answer) also ties the model to a parent property. It works like this: Javascript doesn't see/find 'foo' in the child scope, so it looks for it in the parent scope (due to prototypical inheritance) and finds it there.

To see what the child scope looks like, use your original fiddle, and add this code to your template somewhere:

<a ng-click="showScope($event)">show scope</a>

And add this code to your Ctrl:

$scope.showScope = function(e) {
   console.log(angular.element(e.srcElement).scope());
}

Before you type into the textbox, click the "show scope" link. In the console (I'm using Chrome), you can expand the "Child" scope and see it does not contain a testvalue property yet (which I find surprising, because I don't know how it is displaying the "initial value" in the textbox). You can expand the $parent and you'll see the testvalue property there -- a property with this name appears to only be in the parent scope at this point.

Now, clear the console, type into the textbox, and click the "show scope" link again. You'll see that the "Child" scope now has a new testvalue property. It shadows/hides the parent property. So, things in the child scope see the child scope testvalue property, and things in the parent scope see the parent scope testvalue property.

Update: FYI, I recently wrote an extensive answer/article about scope prototypical inheritance that explains the above concepts in much more detail, with lots of pictures: What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

like image 42
Mark Rajcok Avatar answered Sep 22 '22 08:09

Mark Rajcok