1

really new to Angular here and I have a problem that I need some help with. Basically, I need to have a selection of items that user can click on. When an item is clicked, the page needs to show some of the properties that the item has like it's description, etc. The first part is not a problem, but I'm having trouble with the second part, which is displaying the data. So here is what I have:

On the front end, I have an angular ng-click chooseItem(item) function that takes the clicked item as its paramater:

<div ng-repeat="item in items" class="col-xs-2 col-md-1">
   <div ng-click="chooseItem(item)" class="thumbnail">
        <img src="/images/items/{{item.name}}.png"/>
    </div>
</div>

This is then passed on to the items factory through items.getChosenItemData(item) function. Since the real item data is stored in Mongo and not the factory, this function queries the db to retrieve the item data. This retrieved data is stored into the chosenItem object, which is then passed back to the controller as $scope.chosenItem.

app.factory('items', ['$http', function($http){
    var objects = {
        items: [
            // ... more items before these

            {name: "Pencil"},
            {name: "Pen"}
            /* I use these item objects as keys to the items themselves.
               The ng-repeat iterates through all of the names for each item
               which allows me to display static images for each item to the page.
               There aren't many items, about 100, but they have tons of json information
               so to hardcode it all into here is not an option
               A way to do this without any hardcoding would be nice! */

            // more items after these

        ],

        // this is used to store a currently clicked item's values
        chosenItem: null 

    }

    objects.getChosenItemData = function(name){
        return $http.get('/items/' + name).success(function(data){
            // console.log(data);
            angular.copy(data, objects.chosenItem);
            console.log("Chosen Item: ", objects.chosenItem);
        })
    }
    return objects
}]);
app.controller('MainCtrl', [
   '$scope',
   'items',
    function($scope, items){
       $scope.items = items.items;
       $scope.chosenItem = null;

       $scope.chooseItem = function(item){
           items.getChosenItemData(item.name);
           $scope.chosenItem = items.chosenItem; //chosen item object attribute in factory
           console.log("$scope item: ", $scope.chosenItem);
       }
    }
});

This almost all works. I can query the data of the clicked item successfully, but returning it is another story. Upon first click, the value of $scope.chosenItem is null. Then upon second click, it stores the value of the click item. This also causes the problem where if I click on n amount of items, the value stored is always the value of the n-1 item, not the current item. I need it to store the value of the clicked item on the first click, not the second.

I have a feeling I need to add a callback somewhere in here to make it work, but I'm new to Angular/JS so I'm not sure where it should even go.

Thanks for any help! Also any tips or leads on Angular design patterns would be much appreciated, since I have the feeling that this is a terrible implementation of something that seems rather simple.

thevengefulco
  • 199
  • 1
  • 12
  • Hi, generally you need to apply a better naming convention becase is very difficult to follow the code. Would be also very helpful a plunker to test the code. – thegio Apr 19 '16 at 00:30
  • I see, made some brief changes. Hopefully it clears things up. – thevengefulco Apr 19 '16 at 00:35
  • Note `success` is deprecated, but if you used `then` here and actually returned a value then in your controller you could chain another `then` like `items.getChosenItemData(item.name).then(function(returnedValue){ $scope.item = returnedValue })`. You're returning a promise from the service, so you just need to chain that further in your controller. – Dan Apr 19 '16 at 00:50
  • Okay is clear, you get always the previous value because when you enter the function chooseItem the remote call is not ended therefore you become the previous value and at the beginning is null. – thegio Apr 19 '16 at 00:51
  • (Or also refer to http://stackoverflow.com/questions/12576798/angularjs-how-to-watch-service-variables - you could watch the service variable and update the scope when it's updated). @thegio - yes. – Dan Apr 19 '16 at 00:53
  • @Dan I'm a little confused on what you said about `then`. Is it possible to elaborate? Also, which option do you think would be best option of the two? Thanks for the help – thevengefulco Apr 19 '16 at 01:31
  • I was simply referring to https://docs.angularjs.org/api/ng/service/$http#deprecation-notice. `success` and `error` should be replaced with `.then(successFn, errorFn)`. – Dan Apr 19 '16 at 01:46

1 Answers1

3

I suggest you to expose the service directly:

$scope.serviceItem = items; 

and then you can call it in the view like that:

{{serviceItem.chosenItem}} 

It will be always updated to the latest clicked value.

I hope it helps.

enter image description here

thegio
  • 1,203
  • 6
  • 25
  • @thegio I will try it out and see where it gets me, thanks – thevengefulco Apr 19 '16 at 01:23
  • Here's a plunker with both solutions working side by side. https://plnkr.co/edit/GjZV7VHB7iSKB3YF3L9O?p=preview – Dan Apr 19 '16 at 01:35
  • @Dan so they both equal out to null right? So neither of them work? – thevengefulco Apr 20 '16 at 22:26
  • @thegio your solution worked! Actually it was a mix of both. Thanks guys! – thevengefulco Apr 20 '16 at 22:48
  • @tear728 No, they both work, they start as null / undefined, and when you click the button they both work. Recommended reading: http://joelhooks.com/blog/2013/04/24/modeling-data-and-state-in-your-angularjs-application/ – Dan Apr 21 '16 at 02:24