3

I've been struggling with Angular a bit with understanding scopes and what not.

After inserting a new 'wire' to my array, ng-repeat doesn't update. I've been reading and it could be because my array is out of scope when I add to it (suggesting that I could be adding to other array) but it doesn't seem to be the case?

Here is my code

<body ng-app="wireApp" ng-controller="AddWireController">
<header>
 <form role="form" class="form">
     <div class="form-group">
        <input type="text" placeholder="Description" class="form-control" name="wireDescription" ng-model="wire.description">
        <input type="text" placeholder="URL" class="form-control" name="wireURL" ng-model="wire.URL">
        <input type="text" placeholder="Tags" class="form-control" name="wireTags" ng-model="wire.tags">
        <input type="text" placeholder="Groups" class="form-control" name="wireGroups" ng-model="wire.groups">
     </div>
     <button class="btn btn-primary btn-block" ng-click="addwire(wire)">Add+</button>
    </form>
</header>
<div id="timeline" ng-controller="ListWireController">
    <div ng-repeat="wire in wires">
         <div class="timeline-entry">
            <div class="timeline-stat">
            <div class="timeline-icon bg-info"><i class="fa fa-envelope fa-lg"></i></div>
            <div class="timeline-time">{{ wire.linLastTouched }}</div>
         </div>
            <div class="timeline-label">
            <h4 class="text-info text-lg">{{ wire.linDescription }}</h4>
            <p>{{ wire.tags }}</p>
         </div>
        </div>
    </div>
</div>
</body>

And here is the javascript (angular):

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

//Parent controller
wireApp.controller('AddWireController', ['$scope', function($scope) {

$scope.addwire = function(wire) {
    $.post('/wire/create', wire, function(data) {
        $scope.$broadcast('addwire', data); //emit to children
    });
};

}]);

//Child of AddWireController
wireApp.controller('ListWireController', ['$scope', function($scope) {

$scope.wires = [];

$scope.getwireByGroup = function(groupID) {

    $.get('/wire/grpID=' + groupID, function(data) {
        $.each(data.wires, function(index, key){

            var newKey = key;
            newKey.linLastTouched = jQuery.timeago(newKey.linLastTouched);
            $scope.wires.push(newKey);
        });

    });
};

$scope.$on('addwire', function(event, mass) {
    $scope.addwire(mass);
});

$scope.addwire = function(wire){
    $scope.$apply(function() {
        $scope.wires.push(wire);
    });
}

//init data
$scope.getwireByGroup(0);

}]);

Additional question:

The way this is done it forces me to have a relation between the two controllers given that I use $broadcast, but what if I didn't want to have a relation between the two? Would I need to use a factory with a promise? Could you provide me an example with the code I've provided?

EDIT:

First of all I'd like a huge thanks to Simon H and Keval Bhatt because they helped me understand the problem rather than just help me find a solution.

Here's the working code (angular):

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

wireApp.factory('wireFactory', function($http){

var wires = [];

return {
    getwireByGroup: function(groupID){

        $http.get('/wire/grpID=' + groupID)
            .success(function(data) {
                $.each(data.wires, function(index, key){
                    var newKey = key;
                    newKey.linLastTouched = jQuery.timeago(newKey.linLastTouched);
                    wires.push(newKey);
                });
            });

        return wires;

    },

    addwire: function(wire){

        $http.post('/wire/create', wire)
            .success(function(data) {
                wires.push(data);
            });
    } 
}               
});


//Parent controller
wireApp.controller('AddWireController', function($scope, wireFactory) {

 $scope.addwire = function(wire) {
    wireFactory.addwire(wire);
};

});

//Child of AddwireController
wireApp.controller('ListWireController', function($scope, wireFactory) {

$scope.wires = [];

$scope.getwireByGroup = function(groupID) {
    $scope.wires = wireFactory.getwireByGroup(groupID);
};

$scope.getwireByGroup(0);

});
4
  • stackoverflow.com/a/30505788/4696809 see this answer so no need to use $scope.$apply() because $apply will apply dirty cycle again Commented Oct 21, 2015 at 8:15
  • Thanks for your answer Keval Bhatt. Should I turn to services like in the answer? Commented Oct 21, 2015 at 8:20
  • yes and you can use factory instead of service also Commented Oct 21, 2015 at 8:23
  • Will try it by the end of today - thank you for your answer! Commented Oct 21, 2015 at 8:24

1 Answer 1

3

The reason is that you are mixing Angular with jQuery. When you use Angular functions, such as $http then after data is received it does a 'digest' which updates the view. But Angular does not know about data being received by $.get so it does not update in this case.

My recommendation would be to drop the jquery in favour of angular methods. but if you can't then each time you need an screen update add a $scope.$apply()

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

8 Comments

Hello Simon thanks for your answer. I did not know using jquery would interfere so much I was convinced I needed to turn to promises. Although: Why would it be a problem if the repeat is being done on a variable within the scope and that variable is being 'fed manually' through the push?
It's not that 'interferes' it's just that angular only knows what it knows. It can follow actions that angular itself has initiated, such as $http requests, but not those from any other piece of arbitrary code.
Correct me if I'm wrong: So Angular doesn't know that I am making an $.get so when the actual data is received from the server onto my array, angular doesn't know about it, so it doesn't do anything about it (i.e. update ng-repeat) ?
Exactly. It will if you use $http, which is the right way forward for you. But angular does not have methods for everything - for example I do geolocation in one project and when I get a location back I have to 'wake up' angular with $scope.$apply() so that it renders that data appropriately.
Alright I understood more of the subject now, I'll come back later with an update! Thank you both.
|

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.