0

Before I start, I will link my codepen so you can have a look before reading this :)

I have made a very simple app to demonstrate my issue. basically when I have multiple services sharing an array, it appears that angularjs treats the array as a primitive object which is odd. I have to link code, so this is my controller and 2 services at the start:

angular.module('bindingApp', [])

.controller('MainController', ['MainService', 'SelectionsService', function (service, selections) {

  // Map the controller to a variable
  var self = this;

  // Attach the model to our scope
  self.models = service.models;

  // Create a function that handles the changes the service in some way
  self.updateSelectedItems = function () {

    // Get our first item
    var models = selections.selected;

    // Loop through our selected items
    for(var i = 0; i < models.length; i++) {

      // Get our current model
      var model = models[i];

      // Change the properties
      model.status = 'Cancelled';
      model.colour = 'gray';
    }
  };

  // Reset everything
  self.reset = function () {
    selections.reset();
    service.reset();

    console.log('models in the controller', self.models);
  }

  // Map our function to our service function
  self.selectItem = selections.select;

  // Initialize our service
  service.init();
}])

.service('MainService', function () {

  // Create our service
  var service = {

    // Create the default model (empty array)
    models: [],

    // Populates our model
    init: function () {

      // Loop from 1 to 10
      for(var i = 0; i < 10; i++){

        // Create some object
        var model = {
          status: 'Live',
          colour: 'green',
          selected: false
        };

        // Push our model to our array
        service.models.push(model);
      }

      console.log('models in the service', service.models);
    },

    // Resets everything
    reset: function () {

      // Reset our array
      service.models = [];

      // Initialize
      service.init();
    }
  };

  // Return our service
  return service;
})

.service('SelectionsService', function () {

  // Create our service
  var service = {

    // Create a reference to our selected objects
    selected: [],

    // Our select function
    select: function (e, item) {

      // Create a reference to our selected items
      var selected = service.selected;

      // Update the selected status
      item.selected = true;

      // Push our item to our selected items
      selected.push(item);

      // Stop propagation
      e.stopPropagation();
      e.preventDefault();
    },

    // Resets our selected items
    reset: function () {
      service.selected = [];
    }    
  };

  // Return our service
  return service;
});

I have created 2 more Codepens to try to fix the issue. The first one maps the items to an object encapsulating an array in the MainController. The second one does the same, but also the MainService has an object encapsulating the array.

Does anyone know what I can do to get this simple pen working?

r3plica
  • 13,017
  • 23
  • 128
  • 290

2 Answers2

2

OK. This doesn't have much to do with Angular. Just plain JavaScript.

Here's what happens:

The service initializes its models array. service.models is a variable that contains a reference to that array. You thus have

service.models ---->  [firstArray]

Then the controller does self.models = service.models;. So it creates another reference pointing to the same array, referenced by service.models:

service.models ---->  [firstArray]
                      ^
controller.models ----|

Then you click the reset button, which calls service.reset(), which does service.models = [];. So it creates a new array and assigns it to its models variable. You thus end up with

service.models ---->  []

controller.models --> [firstArray]

Note that you never make controller.models point to the new array in the service. So it still points to the first array, and the view still displays the elements of that first array.

So, either you make sure to reinitialize the controller's models variable after calling reset():

controller.models = service.models;

Or you make sure to simply remove everything from the original, first array in reset():

service.models.splice(0, service.models.length)
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • See http://stackoverflow.com/questions/1232040/how-do-i-empty-an-array-in-javascript for other methods to empty an array. ;-) – Norman8054 Feb 29 '16 at 17:52
1

It looks like that you must not reset the models array by referencing a new empty array but removing all items from it.

Instead

// Reset our array
service.models = [];

use

// Reset our array
service.models.length = 0;
Norman8054
  • 804
  • 7
  • 15