1

I'm using AngularJS 1.5, ui-router, and angular-resource and I am developing a component-based application. I have one parent state, which is used for getting and updating data, this data is bound to multiple child states via a parent state resolver.

When I change the data manually in the parent component controller (e.g. vm.town.x = 666), everything works fine and the change is visible in the child state components. However, when I change data in the parent component controller from the response of the rest service (using angular-resource), the data change is visible only in the parent state component.

state definition:

.state('town', {
  url: '/my-towns/:townId/',
  component: 'town',
  bindings: {
    town: 'townData'
  },
  resolve: {
    townData: function(Town, $stateParams) {
      return Town.get({
        townId: $stateParams.townId
      });
    }
  }
})

.state('town.detail', {
  url: 'detail',
  component: 'townDetail',
  bindings: {
    town: 'townData'
  }
})

parent (town) component controller definition:

function TownCmpController(TownServices,Town,BuildingUpgradeRest) {
  var vm = this;
  this.upgradeBuilding = function(data) {
     vm.town = BuildingUpgradeRest.update({townId:  vm.town.TownId,buildingId: data.building.BuildingId});
}

rest service definition:

.factory('BuildingUpgradeRest',function($resource){
    return   $resource('api/public/v1/myaccount/towns/:townId/buildings/:buildingId/upgrade', {townId:'@townId', buildingId: '@buildingId'}, {
    'update': {
      method: 'PUT'
      }
    });
  })

'town' object binding is same in both components

bindings: {
    town: '<'
  }

Both services return the same object type and both work.

Graham
  • 7,431
  • 18
  • 59
  • 84
chobotek
  • 77
  • 2
  • 6
  • This works initially because you are resolving the town during the transition. When it's successful, both components get the resolve value of `town` bound to their inputs. When you change the value of `vm.town` you are overwriting the reference on the parent controller. But the child controller isn't bound to the parent controller; it's bound to the resolved value. If you look at the DOM you will see `` – Chris T Jan 10 '17 at 15:13
  • (...continued) I suggest you update the `townId` state param so that the town is re-fetched cleanly. If the townId hasn't changed, you can use the `{ reload: 'town' }` transition option to force the town resolve to re-fetch. – Chris T Jan 10 '17 at 15:16
  • Hi, thanks for your answer. I just don't understand, why I can do for example `vm.town.x = 666` in parent component controller and everything works (the changes are visible in child states components). But only change vm.town by calling the service `BuildingUpgradeRest.update()` doesn't work. If I understand your suggestion, it means I need to call my rest services 2x for every change of town object (first call for change, second call in state resolve)? – chobotek Jan 11 '17 at 11:01
  • It is because with `vm.town.x` you are changing a property on an object. Because the *same object is bound in both controllers*, the change is reflected. However, changing `vm.town` actually changes the vm's reference to a *different object*. In the other controller, the reference to the original object is still the old one. – Chris T Jan 11 '17 at 18:06
  • I don't suggest calling REST services twice *each time*. I do suggest reloading the resolve (from the REST service) after you save it. If you definitely need to mutate the data in the child and have it reflect in the parent, you could follow the parent/child communication pattern outlined here: https://ui-router.github.io/guide/ng1/route-to-component#routed-parentchild-component-communication – Chris T Jan 11 '17 at 18:09

1 Answers1

1
function TownCmpController(TownServices,Town,BuildingUpgradeRest) {
  var vm = this;
  this.upgradeBuilding = function(data) {
     BuildingUpgradeRest.update({townId:  vm.town.TownId,buildingId: data.building.BuildingId}).then(function (response) {
       vm.town = response;
     })
  }
}

Your service return promise, so you reslove service response and then setup vm.towns