2

I've read many questions like this but for some reason haven't found why my code isn't working.

The goal is to have the page load with a list of items loaded by ng-repeat, which works fine, but then when the user performs a function, have that ng-repeat array replaced with another one of the same structure. It's got through http.

The code is like this.

// in HomeController

$scope.content = {
    items: [ {
        title: "hi!"
    } ]
}

$scope.search = function() {
    if ( $scope.query == '' )
        return $scope.content = null

    $http
        .get( '/api/search', { params: 
            { terms: $scope.query }
        } )
        .success( function ( results ) {
            console.log( results)
            $scope.content.items = results
        })
        .error( function ( error ) {
            $flash.error = error
        })
}

then

// in the HTML

<div ng-controller="HomeController" class="list-container">

    <div class="panel panel-item" ng-repeat="item in content.items">
        <h2 ng-bind="item.title"></h2> // ... etc

Then elsewhere there is an ng-change that triggers search(). I know the http.get works because I see it in the console. But it doesn't update the main source of ng-repeat or even the scope, from the looks of it.


Is it relevant if this controller is nested in another one?

4
  • provide a plunker. If your http returns in correct format it should work fine as it was working earlier without any problem. Commented Mar 13, 2015 at 6:23
  • If your $http returns a list which contains duplicates, you have to alter ng-repeat like: ng-repeat="item in content.items track by $index" Commented Mar 13, 2015 at 6:45
  • @MadasuK The Plunker seems to work fine: plnkr.co/edit/SWddJIEyOVA27Ix7387F Commented Mar 13, 2015 at 7:24
  • @Noah: Plnkr seems to work, because you haven't executed everything in it that you're doing in your actual code... Check my answer that compares working and invalid code side-by-side. Commented Mar 13, 2015 at 8:08

1 Answer 1

2

Solution

The problem you're having is this line:

return $scope.content = null;

Because at this point you destroy your object $scope.content which means it doesn't have any subordinate properties or anything. So when you afterwards try to assign a value to its property, that property doesn't exist on a null variable you get a runtime error:

Cannot set property 'items' of null

So if you changed upper line to

return $scope.content.items = null;

everything should work. This way your content doesn't get destroyed it just reassigns its inner property a new value.

Or you could also keep your initial line but change assignment afterwards to

$scope.content = {
    items: result
};

So when you get results you recreate the whole content object that may have been destroyed before (assigned to null).

But I would personally suggest you change upper problem code line to this:

$scope.content.items = [];
return null; // change to whatever return value seems appropriate

Which will keep your property as Array as it initially was. You'll just empty it. Sometimes it's best if you think of Javascript as a strong type language and don't execute code that would break in a strongly typed language.

Here's an example with side-by-side comparison of both working versions to the one that you're using and doesn't work.

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

5 Comments

This is true. But it didn't fix my problem. I'll still mark it correct shortly.
@noah but did you find the problem with your code? Was it something related to your code in the question or not?
I'm not sure. Could it be caused by the controller being nested in another one? It goes MainController -> HomeController.
No controller nesting shouldn't be a problem. I would change the ng-repeat to call a function and debug that function to actually see the running values...
I've now made it into a service. For some reason, pushing each item into an empty array seems to work instead of saying items = results, even though results seemed to be an array. Now I have $scope.content = new Content(), with Content being a different but nearly identical service. Then on the search() function I say $scope.content = new Search(), then run the command in Search to populate it, $scope.content.load(). But that doesn't work, the content stays the same.

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.