restangular icon indicating copy to clipboard operation
restangular copied to clipboard

API enhancement: get full route for nested resource

Open donaldpipowitch opened this issue 10 years ago • 8 comments

If I use nested resources I sometimes have to deal with generic route names. Say I have a users and companies route and both have a nested resource address, which I can operate on with users/:id/address and companies/:id/address.

Now I want to enhance the restangularized element with custom logic inside Restangular.setOnElemRestangularized, but I need to treat the address of a user differently than the address of a company. I can't just look into the route param, because it is address in both cases. I need to check elem.parentResource.route, too. It could look like this:

Restangular.setOnElemRestangularized(function(elem, isCollection, route) {
  if(elem.parentResource.route + '/' + route === 'companies/address') { /* do stuff */ }
  if(elem.parentResource.route + '/' + route === 'users/address') { /* do stuff */ }
});

This can become quite verbose and error prone. It becomes even worse with deeper nested resources or in more generic situations where I have to make sanity checks (e.g. is elem.parentResource defined?).

It would be very useful to get the full route of a resource like this:

Restangular.setOnElemRestangularized(function(elem, isCollection, route) {
  if(elem.getFullRoute() === 'companies/address') { /* do stuff */ }
  if(elem.getFullRoute() === 'users/address') { /* do stuff */ }
});

.getFullRoute() would basically recursively prepend every existing parentResource.route separated by a /. elem.getFullRoute() would be equal to elem.route for every non-nested resource.

function getFullRoute(elem) {
  var parentRoute = '';
  if(elem.parentResource) {
    parentRoute = getFullRoute(elem.parentResource) + '/';
  }
  return parentRoute + elem.route;
}

What do you think?

donaldpipowitch avatar Jun 04 '14 06:06 donaldpipowitch

I found this issue while looking for a way to do Restangular.extendModel(...) with a route like 'clubs/members'. I haven't tried yet, but I would love to see the preferred syntax of the extendModel/extendCollection methods to be compatible.

bendalton avatar Jun 09 '14 11:06 bendalton

Just ran into this issue, too. extendModel and extendCollection are effectively useless in the scenario I'm in due to the all or nothing nature of how routes are extended. /user/detail and /customer/detail, for instance.

oneironautics avatar Jun 12 '14 12:06 oneironautics

+1

joshrieken avatar Jul 09 '14 20:07 joshrieken

+1

Rodeoclash avatar Sep 18 '14 05:09 Rodeoclash

I too am running into this. Looking for a good way to extendModel() on a nested resource. In my case, I have:

myApp.factory 'Gallery', (Restangular) ->
  Restangular.service('galleries')

Gallery.one(id).getList("photos")

and I'd like to have all the returned photo objects extended. I tried extending it with the galleries route, but never managed to extend the photo model properly:

  Restangular.extendModel 'galleries/:id/photos', (model) ->
    model.testFunc = (msg) ->
      console.log(msg)
    model

wkoffel avatar Oct 09 '14 16:10 wkoffel

I ran into the same issue. I have customers/contacts and suppliers/contacts which are different.

The next solution seems to work well :

  1. Define the getFullRoute method (this is an iterative version. don't know if recursive whould be better)
function getFullRoute(elem) {
  var currentElem = elem
  var fullRoute = [];

  do {
    fullRoute.splice(0, 0, currentElem.route);
    currentElem = currentElem.parentResource;
  }
  while(currentElem !== null);

  return fullRoute.join('/');
}
  1. Add line to config.transformElem to get the full route of the element and try to get the transformers of the full route before getting the transformers of the route.
config.transformElem = function(elem, isCollection, route, Restangular, force) {
    if (!force && !config.transformLocalElements && !elem[config.restangularFields.fromServer]) {
      return elem;
    }

    var fullRoute = getFullRoute(elem);
    var typeTransformers = config.transformers[fullRoute] || config.transformers[route];
    var changedElem = elem;
    if (typeTransformers) {
        _.each(typeTransformers, function(transformer) {
           changedElem = transformer(isCollection, changedElem);
        });
    }
    return config.onElemRestangularized(changedElem,
      isCollection, route, Restangular);
};

With that small changes, extendModel will work like this :

Restangular.extendModel('customers/contacts', function(model) {
  // ...
});
Restangular.extendModel('suppliers/contacts', function(model) {
  // ...
});

What do you think ?

vincentdieltiens avatar Dec 10 '14 10:12 vincentdieltiens

My solution can be found at : https://github.com/vincentdieltiens/restangular

vincentdieltiens avatar Dec 10 '14 17:12 vincentdieltiens

This issue is still open and still seems relevant. Is there a workaround or a fix? How can I apply custom methods to nested model objects?

end-user avatar Jul 20 '16 15:07 end-user