Search code examples
javascriptangularjsng-controller

Message won't display a second time after being closed


User can click the help icon to display a help message. It will close if the user clicks on the close icon in the message. This can be repeated an indefinite amount of time.

This works if both the help icon and the message with the close icon are inside the ng-controller.

However, if the help icon is outside and the message is inside it (see below), then I can display and close the help message, but it won't work if I try to display it a second time.

What am I missing?

<div ui-content-for="title">
  <span>Page Title</span>
  <span>
    <i ng-click="isHelpVisible = true;" class="fa fa-question-circle">
    </i>
  </span>
</div>

<div ng-controller="InventoryController as inventory">
  <div class="scrollable">
    <div ng-show="isHelpVisible" class="alert alert-info alert-dismissible">
        <a class="close" ng-click="isHelpVisible = false;"
           aria-label="close" data-dismiss="alert">&times;</a>
        Help message is here.
    </div>
  </div>
</div>

Solution

  • This is a data hiding problem caused by the fact that the ng-controller directive creates a child scope.

    Instead of setting a scope property directly, set a property of an object on the parent scope.

    <div ui-content-for="title">
      <span>Page Title</span>
      <span><i ng-click="help={isHelpVisible: true}" class="fa fa-question-circle"></i></span>
    </div>
    
    <div ng-controller="InventoryController as inventory">
      <div class="scrollable">
        <div ng-show="help.isHelpVisible" class="alert alert-info alert-dismissible">
            <a class="close" ng-click="help.isHelpVisible=false;"
               aria-label="close" data-dismiss="alert">&times;</a>
            Help message is here.
        </div>
      </div>
    </div>
    

    Scope inheritance is normally straightfoward... until you need 2-way data binding. If you try to bind to a primitive (e.g., number, string, boolean) in the parent scope from inside the child scope. It doesn't work the way most people expect it should work. The child scope gets its own property that hides/shadows the parent property of the same name.

    Your workaround is to define objects in the parent for your model, then reference a property of that object in the child.

    For more information, see