1

Starting with the following working fiddle:

http://jsfiddle.net/77vXu/14/

I added a few changes to add a show/hide button

http://jsfiddle.net/77vXu/27/

var myApp = angular.module('myApp', []);

myApp.controller('test', function($scope) {
    $scope.show = false;
    $scope.cancelMessage = '';
    $scope.clickTest = function(){
        alert($scope.cancelMessage);
    };
    $scope.toggleShow = function(){
        $scope.show = !$scope.show;
    }
});

But this completely breaks the character counter. What have I done wrong?

Hoa
  • 19,858
  • 28
  • 78
  • 107

3 Answers3

2

From angularjs :Note that when an element is removed using ngIf its scope is destroyed and a new scope is created when the element is restored. The scope created within ngIf inherits from its parent scope using prototypal inheritance. An important implication of this is if ngModel is used within ngIf to bind to a javascript primitive defined in the parent scope. In this case any modifications made to the variable within the child scope will override (hide) the value in the parent scope.

Solution 1. Please remove ng-if from textarea see here : http://jsfiddle.net/Tex3P/

<div ng-app="myApp">
    <div ng-controller="test">
        <button ng-if="!show" ng-click="toggleShow()">show me</button>
        <div ng-if="show">
            <textarea ng-model="cancelMessage" ></textarea>
<span > {{100 - cancelMessage.length}} characters remaining</span>

            <button ng-click="clickTest()" ng-if="show">clickTest</button>
        </div>
    </div>
</div>

Solution 2.

Define cancelMessage as a object. http://jsfiddle.net/cnre6/

<div ng-app="myApp">
    <div ng-controller="test">
        <p>f{{cancelMessage}}</p>
        <button ng-if="!show" ng-click="toggleShow()">show me</button>
        <textarea ng-model="cancelMessage" ng-if="show"></textarea>
        <span ng-if="show"> {{100 - cancelMessage.length}} characters remaining</span>

        <button ng-click="clickTest()" ng-if="show">clickTest</button>
    </div>
</div>

var myApp = angular.module('myApp', []);

myApp.controller('test', function ($scope) {
    $scope.show = false;
    $scope.cancelMessage = {};
    $scope.clickTest = function () {
        alert($scope.cancelMessage);
    };
    $scope.toggleShow = function () {
        $scope.show = !$scope.show;
    }
});
sylwester
  • 16,498
  • 1
  • 25
  • 33
0

The reason it does not work is because of the way scope variables behave when they're assigned within a child scope and your model does not have a '.' in it. ng-if creates a child scope and since your ng-model does not have a '.' in it it will assign a scope variable named 'cancelMessage' in the child scope that shadows the scope variable in the 'test' controller's scope with the same name - effectively breaking two-way model binding as soon as text is entered in the textarea.

To fix this, you should have a '.' in your ng-model:

<textarea ng-model="cancelMessage.test" ng-if="show"></textarea>

By having a '.', angular will resolve what's left of the dot first, and will find the reference defined in the 'test' controller. It then binds the 'test' property of the 'cancelMessage' model.

The important point is, binding is resolving to the same model (the model which is defined on the 'test' controller's scope.

Infamous Dot in ng-Model (by Design)

Demo Plunker

Community
  • 1
  • 1
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
0

If you refer to AngularJS documentation on ng-if, it says

"The ngIf directive removes or recreates a portion of the DOM tree based on an {expression}. If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM." (https://docs.angularjs.org/api/ng/directive/ngIf)

One thing you can do is hide/show it instead of deleting it from DOM using ng-show or ng-hide

I demonstrate this in this fiddle : http://jsfiddle.net/lookman/0rfz6d1v/

<div ng-app="myApp">
    <div ng-controller="test">
        <button ng-if="!show" ng-click="toggleShow()">show me</button>
        <div ng-show="show">
            <textarea ng-model="cancelMessage" ></textarea>
<span > {{100 - cancelMessage.length}} characters remaining</span>

            <button ng-click="clickTest()">clickTest</button>
        </div>
    </div>
</div>
geckob
  • 7,680
  • 5
  • 30
  • 39