0

Furthering my project but having a hiccup with databinding.

the change in my data is not getting reflected on the DOM

I've a constructor function inside JS function/object.

constructor: function() {
    var self = this;
    var navigation = angular.module("navigation", []);
    navigation.controller("ProductIDsController", function($scope) {
        $scope.productIds = self.productIds;
    });
    angular.bootstrap(document.getElementById('navigation'), ['navigation']);
}

and product id's are defined on the same level

productIds: ["abc", "xyz", "test"], //DOM gets populated from this array via angular

init: function(productIds) {
    console.log(this.productIds); // displays ["abc", "xyz", "test"]
    this.productIds.push("another item"); //this didn't work on the dom either
    this.productIds = productIds; //I changed the productId's by passing another array
    console.log(this.productIds); //the array got changed but DOM is still the same, 
}

HTML

    <div id="navigation">
        <ul data-ng-controller="ProductIDsController">
            <li data-ng-repeat="productId in productIds">{{productId}}</li>
        </ul>
    </div>

Initially the DOM gets populated by the given array, but it's not changing after I pass in another array. how can I have data bind productId's in the given scenario?

Edit: JS Fiddle

http://jsfiddle.net/casadev/n50ecw5m/

2
  • it is not being changed because the productsIds array is outside the angular scope. Commented Sep 19, 2014 at 19:39
  • I guess the arrays are passed by reference, any change in the array should be reflected there Commented Sep 19, 2014 at 19:40

3 Answers 3

2

You're running into a classic Javascript mistake, nothing to do with AngularJS. In Javascript, arrays and objects are always passed by reference. Assume the following:

this.productIds = [1,2,3]
$scope.productIds = this.productIds;

This will make an array, let's call it "A". It will then put a reference to that array in this.productIds and $scope.productIds.

If you now do this:

this.productIds = [4,5,6];
console.log(this.productIds);
console.log($scope.productIds);

then you will get:

[4,5,6]
[1,2,3]

Why? Because setting this.productIds doesn't change the array. It changes which array this.productIds POINTS TO.

There are a lot of options for fixing this. Here's a quick hack:

this.productIds.length = 0; // Truncate the existing array instead of making a new one
angular.forEach(productIds, function(entry) {
    this.productIds.push(entry); // Copy the elements into our existing array
});

This isn't necessarily the most efficient, but it'll show you exactly what's going on.

Sign up to request clarification or add additional context in comments.

5 Comments

I even tried to change the existing array, inside the init function but no change in the DOM this.productIds.push("another item");
That's still the right way to do it. You just need to use it in conjunction with @kechol's comment below about calling $scope.$apply() afterward. Probably you're doing this in some JS code of your own outside Angular's digest loop / watch cycle and it isn't seeing you do it. Try it - it's a 1-line code fix for a lot of "I want to love Angular but haven't converted every piece of my app yet" stuff.
awesome, I've added jsfiddle, seems I'm getting closer
I know puremvc could be daunting but I've updated the fiddle with the $scope approach, do you guys approve this? jsfiddle.net/casadev/n50ecw5m/5
Thanks Chad, great help
1

When you change the value outside of scope, you have to call $scope.$apply() explicitly. https://docs.angularjs.org/guide/scope

UPDATE

http://jsfiddle.net/qv31awmq/2/

puremvc.define({
    name: "modules.search.view.components.Navigation",

    constructor: function () {
        var self = this;
        var navigation = angular.module("navigation", []);
        navigation.controller("ProductIDsController", function ($scope) {
            self.$scope = $scope;
            $scope.productIds = self.productIds;
        });
        angular.bootstrap(document.getElementById('navigation'), ['navigation']);
    }
}, {
    delegate: null,
    $scope: null,
    productIds: ["abc", "xyz", "test"],

    init: function (productIds) {
        var self = this;
        // http://stackoverflow.com/questions/25941124/angular-data-binding-with-passed-params/25941351#25941351
        self.productIds.length = 0;
        angular.forEach(productIds, function (entry) {
            self.productIds.push(entry);
        });
        self.$scope.$apply();
    }
}, {});

var nav = new modules.search.view.components.Navigation();
nav.init(['foo', 'bar']);

6 Comments

Sorry I'm new to angular, can you please help in the above scenario on where and how I do write this line
do you have jsfiddle?
a better approach is to wrap the code making change outside of the angular scope in a $timeout with no interval set. This is the recommend way to get a digest to run after change outside scope, in a safe manner.
@Kechol sorry this, one jsfiddle.net/casadev/n50ecw5m/1 (didn't instanitate the object - fixed), anyway the above url was set as base as well
awesome work, you've helped me to integrate puremvc with angular :)
|
0

I think the best way to do that would be to use a service to broadcast changes in productIds.

navigation.factory('ProductSvc', 
['$rootScope', function($rootScope) {
    return {
        productIds : [],
        changeProductIds: function(newIds){
            this.productIds = newIds
            $rootScope.$broadcast('changeIds');
        }
    }
}])

Controller linked to service :

navigation.controller("ProductIDsController", ['ProductSvc'], 
function($scope, productSvc) {
    ...
    $scope.$on('changeIds', function() {
            $scope.productIds = ProductSvc.productIds;
    })
}

Change your productId via the service (in a controller which handles user input for example)

ProductSvc.changeProductIds(newIds)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.