2

I'm tring to code a little search input to get data from a database using ngResource.

the data are shown in the page with a ng-repeat, but when i do the search and the $scope has been updated, the view is not updated and show old data.

Here is the code:

main.html (active view)

<div ng-controller="searchCtrl as searchCtrl" layout="column">
    <form class="form-inline search-form col-md-offset-1">
        <div class="form-group col-md-5">
            <label class="sr-only" for="search_location">Location</label> <input
                id="search_location" type="search" class="form-control"
                ng-Autocomplete ng-model="place" placeholder="Location" />
        </div>
        <div class="form-group col-md-5">
            <label class="sr-only" for="search_tags">Tags</label> <input
                style="width: 100%;" id="search_tags" type="search"
                class="form-control" id="search_tags" placeholder="Tags">
        </div>

        <div class="col-md-1">
            <md-button class="md-fab md-mini" aria-label="Search" ng-click="searchCtrl.search()"> <md-icon class="md-fab-center"
                md-font-icon="glyphicon glyphicon-search" style="color: black;"></md-icon>
            </md-button>
        </div>
    </form>
</div>

<div ng-controller="mainCtrl">

    <div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>

</div>

main.js

'use strict';
app.factory('Eventi', function($resource) {
    return $resource('/eventsws/events/:location', {location : '@location'}, { 
        search: {
            method: 'GET',
            params: {
                'location' : "@location"
            },
            isArray : true
        }
    })
});

app.controller('mainCtrl', function($scope, Eventi) {
    $scope.eventi = Eventi.query();
});

searchbar.js

'use strict';
app.controller('searchCtrl', function($scope, Eventi) {
    $scope.place = null;

    this.search = function() {

        $scope.eventi = Eventi.search({
            'location' : $scope.place
        });
    }
});

when it start it get all the data from the database and display them correctly, when i try to make a search, the $scope.eventi is updated (i can see the new data in $scope.eventi from the debug) but the view still show the old data and never update.

I've tried to use $scope.$apply at the end of the search function but the result is the same.

Have you any idea why it's not working?

Thanks for your time.

Marco Faion
  • 607
  • 3
  • 14
  • 23
  • The $scope.eventi you see in the debug is the one in your searchCtrl and not the one from your mainCtrl. To update your mainCtrl $scope.eventi you have to find an other way. (A clean but long solution would be using services to shares variables in your controllers, a weird but short solution would be to use $broadcast and $on). If you wan a clean exemple of how to share a service data between controller feel free to ask. But it'll take some times to build it in a plunker. – Okazari May 28 '15 at 14:09
  • Thank you, i've tried and i can see the shared properties i've defined with the service, i'm breaking in the mainCtrl now to double check the $scope of that controller and i can see it updated, but the view still show the old data :( – Marco Faion May 28 '15 at 14:51

2 Answers2

5

The $scope.eventi you see in the debug is the one in your searchCtrl and not the one from your mainCtrl. To update your mainCtrl $scope.eventi you have to find an other way.

A clean but long solution would be using services to shares variables in your controllers.

To answer the question in comments :

i can see it updated, but the view still show the old data

I guess what's the problem (even if i actually didn't see your code).

Problem

If you bind your var like this :

Service

[...]
service.serviceVar = 1;
return service
[...]

This will create a "1" var with a reference.

Controller

  [...]
  $scope.myvar = Service.serviceVar;
  [...]

This will bind $scope.myvar to the "1" reference.

If you do this in your service or in an other controller :

   service.serviceVar = 2;

You will create a new var "2" with a new reference and you will assign this reference to service.serviceVar. Badly all your old references to the old 1 var will not update.

Solution

To avoid that do it like this :

Service

[...]
service.servicevar = {};
service.servicevar.value = 1;
return service
[...]

You create an object with a new reference and assign it to servicevar. You create a var "1" and assign it to servicevar.value.

Controller

[...]
$scope.myvar = Service.servicevar;
[...]

You assign the servicevar reference to your scope var.

view

{{myvar.value}}

You can use the value by using the property of your var.

Updating the var doing this :

service.servicevar.value = 2;

You will create a new var "2" with a new reference and replace the old reference by this one.

BUT this time you keep all your references to servicevar in your controllers.

I hope i was clear and it answer your question.

EDIT :

Try to never ever use $scope.$apply. It's a really bad practice. If you use that to make something works, you should probably find an other to do that (And it will be a great question for Stacks i guess : "Why do i need $apply to solve my problem XXXXX")

rsnorman15 has a good point about your uses of asynchronous calls. Take a look at his answer too.

Here is one of my old plunker using a service to share properties

Okazari
  • 4,597
  • 1
  • 15
  • 27
2

Just change:

$scope.eventi = Eventi.search({
   'location' : $scope.place
});

to

Eventi.search({
  'location' : $scope.place
}, function(eventi) {
  $scope.eventi = eventi
});

It's an asynchronous call so it must be assigned in the success handler.

Another issue you are running into is your ng-repeat is not contained within the div that searchCtrl is scoped. Update your HTML so that it is contained like so:

<div ng-controller="searchCtrl as searchCtrl" layout="column">
  <form class="form-inline search-form col-md-offset-1">
    ... form stuff
  </form>

  <div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>
</div>
rsnorman15
  • 510
  • 3
  • 8
  • Thank you, i've tried to implement your solution, even with the service proposed by Okazari, the model seem updated when i debug the code, but the view still show old data :( – Marco Faion May 28 '15 at 14:52
  • Ahh, I see your issue now. You don't have your `ng-repeat` in the correct div with the search controller. Will update my answer. – rsnorman15 May 28 '15 at 14:56
  • Thanks for the edit, i'll give it a try taking all the code in one controller, but isn't there any solution to make a controller update another model then firing view update? – Marco Faion May 28 '15 at 14:59
  • Taking all the code in one single controller solve the issue, but i really don't want all the application in a single controller :( – Marco Faion May 28 '15 at 15:02
  • Yeah, I definitely agree. @Okazari is correct that it'll take a bit to build an example but there are plenty solutions and tutorials for sharing data between controllers: here is a good video https://www.youtube.com/watch?v=1OALSkJGsRw and here is a SO answer https://stackoverflow.com/questions/9293423/can-one-controller-call-another – rsnorman15 May 28 '15 at 15:05