angularjs - ng-switch does not bind ng-model

I have this repro http://embed.plnkr.co/nVCmukG5abpi1Y4ZHkrq that show when I click 'Title3' and enter a value in text box although the entered value shows reflected in the UI, when I click the 'click' button nothing is binded for the scope attribute $scope.test.

I don't know what is wrong with ng-switch or maybe I'm doing something wrong. Help is appreciated!!!

http://embed.plnkr.co/nVCmukG5abpi1Y4ZHkrq


Solution 1:

This is a scope inheritance problem due to ng-switch creating its own scope.

One recommendation made often is always to use a dot on models. The reason is that when the controller scope item is an object and not a primitive, sub scopes will create a reference to the initial object. If model is a primitive it will not update the original.

For example:

<input ng-model="test.value" placeholder="pre" type="text" />
$scope.test={value:''}

Another approach is to use $parent in html model markup:

<input ng-model="$parent.test" placeholder="pre" type="text" />

Using the dot methodology is a good practice to avoid these issues as you don't need to think about deeper nested scopes.

Demo using test.value as model: http://plnkr.co/edit/CkiF55bLXsYzR6ZjcrJp?p=preview

Reference regarding dot in models(valuable reading): https://github.com/angular/angular.js/wiki/Understanding-Scopes

Solution 2:

This is because you're actually creating a child scope inside of the ng-switch. So another test property exists on a scope belonging to the ngSwitch directive. It will initially show the value from it's parent scope, but when you edit it, because it is a primitive, it only edits the value on the child, not the parent. Prototypical inheritance does not come into play here (but that's what we need).

When you click the button the button is alerting/console.logging the property on the parent scope... which the child cannot change.

To fix this use $parent.test on your ng-model attribute in your ngSwitch:

a snippet:

<span class="pew"  ng-switch-when="title2">
  <input ng-model="$parent.test" placeholder="pre" type="text" />
  {{test}}
</span>

And here's a fork of your plunker showing it in action.

Solution 3:

I've encountered similar issue, and I've solved by creating a scope variable in the controller and used that with in ng-include and ng-switch. This way if you've deep nested ng-include's with in ng-switch and it goes on, we can still directly use that scope variable.

As all child scopes (here, ng-include/ng-switch) extends from parent scope (generally, controllers scope), we can access parent scope directly from with in these child scopes without a problem.

Using $parent will require to write like $parent.$parent.$parent.someProp

Example Plunk: http://plnkr.co/edit/8UGH7nUpFmATiXfkYSwr?p=preview