1

I have an application that has a main display which will contain a number of child elements, where I want to use a "template" for each element, and then later update properties on each of these as I have data coming in from a service.

So, I have this in the "main display"

<div ng-controller="Main as vm">    
<div style="display:inline-block"
     ng-repeat="e in vm.car"         
     ng-include="'app/car/car.html'" />    
</div>

[EDIT] I removed the ng-controller="Car" form the above

The main controller code..

function Main($scope) {
  var vm = this;
  vm.car = [];
  var i;
  for (i = 1; i <= 100; i++)
    vm.car.push({ title: "Car 00" + i });
}

and the Car controller is as follows..

(function () {
'use strict';

angular
    .module('app.car')
    .controller('Car', Car);

car.$inject = ['$scope', 'carservice'];

var localViewModel; // EDIT
function Car($scope, carservice) {
  // $scope comes in as the parent scope
  var e = $scope.vm;
  var i = $scope.$index;

  // EDIT
  localViewModel= $scope.evm;

  localViewModel.title = e.car[i].title;

  // Pass in a call back for server changes on this object
  carservice.subscribeChangeEvent(localViewModel.title, $scope, onChange)

  localViewModel.properties = [];
  localViewModel.properties.push("Dest A");
  localViewModel.properties.push("Ammie Grey");      
};

function onChange(msg, data) {
  if (msg == "title")
    localViewModel.title = data;
}
})();

Finally, the Car template html is as follows..

<div ng-controller="Car as evm" class="car-card" style="padding: 0px">
   <div class="cartitle">
      <div class="cartext" style="color:white;font-size:1.1em">{{evm.title}}   </div>
     </div>
   <ul class="carul" ng-repeat="p in evm.properties">
      <li>{{p}}</li>                
   </ul>
  </div>

When I first display it, all seems to render as expected. My problems is when I want to update a property on the "Car".

There are a couple of things here I just don't understand

  • In the Car controller, I had to call the "vm" a different name to vm, (ie I called it "evm", when I used "vm" it just did not appear to work.

  • My actual problem here is when I try to update one of the properties via the onChanged callback, ie the line evm.title = data;. Here the DOM does not update. I can see a new value being set on the evm.title, but the display just does not update.

Does anyone know what could be wrong here, am I using the totally wrong approach, or should I not be using the "Controller As" in this "nested" case?

Thanks in advance for any suggestions!

peterc
  • 6,921
  • 9
  • 65
  • 131
  • 1
    can you provide fiddle ? – Anik Islam Abhi Dec 22 '15 at 05:06
  • You have both `ng-controller="Car"` and `ng-controller="Car as evm"`, is that by choice? – tasseKATT Dec 22 '15 at 05:51
  • @AnikIslamAbhi I don't think I can do a fiddle using the `ng-include="'app/car/car.html'"` – peterc Dec 22 '15 at 10:26
  • @tasseKATT See edits above, I removed the duplication of the Car controller which hopefully makes it a little clearer. Unfortunately the DOM still does not update (to localViewModel.title where localViewModel is set to `localViewModel= $scope.evm` – peterc Dec 22 '15 at 10:50
  • I will take a look :) – tasseKATT Dec 22 '15 at 10:50
  • @peterc You can use `ng-include` with a Plunker. (Although it seems to be down today...) – Elfayer Dec 22 '15 at 12:44
  • @peterc I don't know what you are doing in `carservice.subscribeChangeEvent`.But when you change value on a service, to update the view, you need to use `$scope.$watch` to manually apply the changes to the `vm/$scope` variable. – Elfayer Dec 22 '15 at 12:50
  • @Elfayer Yes I tried to go to Plunker , and could not get there (looks like it is down for others too). In the `carservice.subscribeChangeEvent` (as this is a test app) it is just listening out out for a button click via another view, using similar method as discussed [here](http://stackoverflow.com/questions/11252780/whats-the-correct-way-to-communicate-between-controllers-in-angularjs). In the end it is just some way to call the `onChange` function and update the property. Do I need to use `$watch` in this case? – peterc Dec 22 '15 at 13:19
  • @Elfayer I have added the following in the equipment controller... `$scope.$watch(function (scope) { return scope.evm.title }, function (newValue, oldValue) { $scope.evm.title = newValue; } );` When the onChanged function is called, the second "listener" function is called (it hits a breakpoint), but I am not sure what else to do here? newValue is set to the new text as set in the onChange function, but then the `$scope.evm.title = newValue;` is what I am already doing anyway (and as expected the DOM is still not updated) – peterc Dec 22 '15 at 13:53

1 Answers1

0

While putting together the Plunker for this (just remove the one service to simplify), I found my problem. The localViewModel; and onChanged was not in the correct scope. Crazily, debugging in Plunker helped me pick it up.

So the Car controller needs to have the onChanged AND localViewModel; function scoped inside of the function Car, so it becomes...

(function () {
 'use strict';

  ...
 function Car($scope, msgservice) {
   // $scope comes in as the parent scope
   var e = $scope.vm;
   var i = $scope.$index;

   var localViewModel; // THIS IN HERE
   var id;

   localViewModel= $scope.evm;
   localViewModel.title = e.car[i].title;
   id = e.car[i].title;

   // Pass in a call back for server changes on this object
   msgservice.subscribeMessage('title', $scope, onChange);

   localViewModel.properties = [];
   localViewModel.properties.push("Dest A");
   localViewModel.properties.push("Ammie Grey");      

  // THIS IN HERE TO GET TO LOCAL localViewModel
  function onChange(msg, data) {
    if (id != "CAR 001")
      return;

    localViewModel.title = data;
   }
 }
})();

Thanks to @Elfayer for your suggestions along the way.

peterc
  • 6,921
  • 9
  • 65
  • 131