Search code examples
angularjsangularjs-ng-repeatbootbox

ng-repeat only updating after clicking another tab or typing in a textbox


I'm pretty new to angular and have been having a bit of a problem in trying to create a basic "to-do" list sort of app.

There are various categories in the sidebar, and the user can click a button that brings up a modal prompting the user for the name of a new category. This name is used to create a new category, which is pushed onto the preexisting array.

However, the new category is only appearing after I start typing in another text-box on the screen or click on another tab.

The code that should be relevant:

var list = this;

$(document).on("click", ".prompt", function(e) {
bootbox.prompt("What do you want your new category to be?", function(result) {                
    if(result !== null) {
        list.addCategory(result);
    }
});
});

this.addCategory = function(result) {
  if(result.trim() != "") {
    var newCategory = new Category(result);
    list.categories.push(newCategory);
    this.setCategory(newCategory);
  }
};

I can't seem to figure out how to post HTML as a code block, but here's the directives used to list out the categories (with categoryCtrl being the controller in question): ng-class="{active: categoryCtrl.isSet(category) }" ng-repeat="category in categoryCtrl.categories" ng-init="categoryCtrl.currCategory = categoryCtrl.categories[0]"

I know that the array is being updated immediately - if I add an alert 'bootbox.alert(list.categories[list.categories.length-1].name)' the alert gives me whatever the input was like it's supposed to. It's just not showing up in the ng-repeat.

Another interesting observations is that the ng-init overrides the this.setCategory(newCategory) - so it seems that when the list does update, it is reverting to its ng-init value.

Other places where I have an ng-repeat of an array, it's updated automatically when something new is pushed onto it. I'm wondering if it may have something to do with the modal/usage of bootbox - everywhere else things are added either by a checkbox or keying something into a textbox on screen, this is the only place where a modal is used.


Solution

  • Here is a working plunker based on your code.

    The app looks like below. I initialize an array with dummy data for the example, but an empty array would work too. I used the vm = this syntax similar to what you have. When calling $nbBootbox.prompt it returns a promise so you need to use the then() syntax like below:

    var app = angular.module('plunker', ['ngBootbox']);
    
        app.controller('MainCtrl', ['$scope', '$ngBootbox', function($scope, $ngBootbox) {
          var vm = this;
    
          vm.name = 'World';
          vm.categories = ['Category 1', 'Category 2'];
    
          vm.prompt = function() {
    
            $ngBootbox.prompt('Enter a new category?')
              .then(function(result) {
                console.log('Prompt returned: ' + result);
                vm.categories.push(result);
              }, function() {
                console.log('Prompt dismissed!');
              });
    
          }
        }]);
    

    To make your HTML more angular like I changed it to this and also use the ControllerAs syntax:

    <body ng-controller="MainCtrl as vm">
      <p>Hello {{vm.name}} !</p>
      <ul>
        <li ng-repeat="c in vm.categories">{{c}}</li>
      </ul>
      <a href="" ng-click="vm.prompt()">Add Category</a>
    </body>
    

    So, the link calls the prompt() function... it opens the modal and if you enter in the category, I push it to the categories array and it is added automatically to the page as a new bullet point in the list of categories.

    From the documentation: $ngBootbox.prompt(msg)

    Returns a promise that is resolved when submitted and rejected if dismissed.

    Example

    $ngBootbox.prompt('Enter something')
        .then(function(result) {
            console.log('Prompt returned: ' + result);
        }, function() {
            console.log('Prompt dismissed!');
        });
    

    Hope this helps. let us know.