Restangular: New Angular service to handle Restful Resources properly and easily

6,820 views
Skip to first unread message

Gonto

unread,
Apr 9, 2013, 10:51:40 PM4/9/13
to ang...@googlegroups.com
Hey guys,

I've developer Restangular, an AngularJS service that will help you get, delete and update Restfull Resources with very few lines and very concise.

If you want, you can take at the blog post and in Github:



Thanks!

Alec Whittington

unread,
Apr 10, 2013, 12:38:25 PM4/10/13
to ang...@googlegroups.com
Gonto,
     I like what you've done. I can see some places in my code where I would use this.

Thanks for sharing,
Alec

Martin Gontovnikas

unread,
Apr 10, 2013, 12:59:00 PM4/10/13
to ang...@googlegroups.com
Hey,

Thanks for the comment! If you find any issue or if you need something that's not implemented, please report this in Github.

Bests,
Gonto
--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/QA-irGz4zqM/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Andrea Reginato

unread,
Apr 11, 2013, 4:40:27 AM4/11/13
to ang...@googlegroups.com
Nice job!

Mason Jones

unread,
Apr 12, 2013, 7:59:53 PM4/12/13
to ang...@googlegroups.com
I've just started using this today, I like it quite a bit! I do have a question; if it's a bug I can put something onto Github but I suspect I'm just missing something.

In this example the code is getting a company and then a list of its owners:

    var baseCompanies = Restangular.all('companies');
    var company = Restangular.one("companies", company_id);
    $scope.owners = company.getList("owners");

This generates a server request that's just right, and the list of owners is put into $scope.owners. But when I later try to iterate $scope.owners to delete one, I wasn't getting the models, but intermediate objects. I debugged it and found a way to do it, but it obviously looks like a hack:

    for( var i =0; i < $scope.owners.$$v.length; i++ ) {
      var owner = $scope.owners.$$v[i];
      if(owner.id === id) {
        owner.remove();
        $scope.owners.$$v.splice(i,1);
        return;
      }
    }

As you can see, I couldn't simply access $scope.owners[i] -- I had to dig into the object and access $scope.owners.$$v[i], which doesn't seem right. Is there a better way to do this?

Thanks for the library, it's really convenient!


On Tuesday, April 9, 2013 7:51:40 PM UTC-7, Gonto wrote:

Gonto

unread,
Apr 13, 2013, 12:11:24 AM4/13/13
to ang...@googlegroups.com
Hey,

First of all, thanks for the comments.

Actually, all cals from this Library return a Promise of a response, not really the response. This uses $q from AngularJS.

You can treat this response as real values in your templates as AngularJS knows how to use Promises which is really cool. So, if in your template you use an ng-repeat="owner in owners" you'll get the real owner info :).

However, from your code this is still a promise of a result, so the right way of using it is by setting a callback in the then, so your iteration would be:

$scope.owners.then(function(owners) {
  // Here do the real iteration :).
var  _.find(owners, function(one) {
    return 
  })
});

Gonto

unread,
Apr 13, 2013, 12:13:32 AM4/13/13
to ang...@googlegroups.com
Sorry, it got cut in the middle :) 

$scope.owners.then(function(owners) {
  // Here do the real iteration :).
var ownerToDelete =   _.find(owners, function(one) {
    return one.id === ownerId;
  });
  ownerToDelete.remove();
});

I hope this makes it clear. $resource instead of using Promises actually returns right away an empty object or an empty array and then fills in the inforamtion. Instead of doing this approach I've chosed to use promise, as it's much easier to handle errors this way:

$scope.owners.then(function(owners){
  // Your stuff
}, function(errors) {}
  // Damn, there was an error
 );

Gonto

unread,
Apr 13, 2013, 12:17:00 AM4/13/13
to ang...@googlegroups.com
Promises are also used in $http :), so instead of then, you can use success and error if you'd rather:


Bests,
Gonto

Mason Jones

unread,
Apr 13, 2013, 1:44:22 AM4/13/13
to ang...@googlegroups.com
Thanks for your quick response. Yes, this does make sense, actually; I hadn't quite thought it through that even long after the data was loaded, in a separate click-driven event, it still needs to use then().

Here's a follow-up question, as I'm working on using Restangular in an autocomplete function as well... I'm having the trouble that when the user types something, it's not expected to return without the data:

$scope.doGetAutocomplete = function (request, response) {
    var allUsers = Restangular.all('users.json');
    allUsers.getList('', {query: $scope.ownerSearch}).then(function(data) {
      response(data.suggestions);
    });
};

This "works" except that the doGetAutocomplete() function returns immediately, which blows up. What's the best way to block the return until the then() function finishes?

Thanks again, I appreciate the tips.




--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/QA-irGz4zqM/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--


Mason Jones - Co-Founder/CTO, FinderLabs

Mason Jones

unread,
Apr 13, 2013, 1:55:42 AM4/13/13
to ang...@googlegroups.com
Actually, never mind my follow-up question here; obviously it needs to be able to handle the delayed data, it's just not doing it properly right now...

Gonto

unread,
Apr 13, 2013, 1:23:43 PM4/13/13
to ang...@googlegroups.com
Hey,

You're absolutely right.

The TypeAhead library must be able to receive data async, as that's one of the main features of it. Check out AngularStrap, I've used it with Restangular and it works great :).

  1. <!-- Async function defined in your controller -->
  2. $scope.typeaheadFn = function(query, callback) {
  3. $http.get('/stations/autocomplete?term='+query).success(function(stations) {
  4. callback(stations); // This will automatically open the popup with retrieved results
  5. });

Bests,
Gonto

Pawel Kozlowski

unread,
Apr 13, 2013, 1:26:08 PM4/13/13
to ang...@googlegroups.com
Hi!

On Sat, Apr 13, 2013 at 7:23 PM, Gonto <gon...@gmail.com> wrote:
> The TypeAhead library must be able to receive data async, as that's one of
> the main features of it. Check out AngularStrap

Or a typeahead widget from http://angular-ui.github.io/bootstrap/
which works with promises nativelly.

Cheers,
Pawel



--
Looking for bootstrap-based widget library for AngularJS?
http://angular-ui.github.com/bootstrap/

Mason Jones

unread,
Apr 13, 2013, 6:34:10 PM4/13/13
to ang...@googlegroups.com
I like that bootstrap type ahead but I need one that does autocomplete based on a server query. Does anyone know of an example using one of these libraries in that way?

Thanks for the ideas!

Pawel Kozlowski

unread,
Apr 14, 2013, 3:41:15 AM4/14/13
to ang...@googlegroups.com
On Sun, Apr 14, 2013 at 12:34 AM, Mason Jones <ma...@finderlabs.com> wrote:
> I like that bootstrap type ahead but I need one that does autocomplete based on a server query. Does anyone know of an example using one of these libraries in that way?

Sure, for the http://angular-ui.github.io/bootstrap/ it is pretty easy
as it is native AngularJS directive that is well integrated with
AngularJS $q promises. Basically what you need to do is to return a
promise that will eventually resolve to an array with suggestions
(based on user's input), ex.:

$scope.cities = function(cityName) {
return $http.jsonp("http://gd.geobytes.com/AutoCompleteCity?callback=JSON_CALLBACK
&filter=US&q="+cityName);
};

I don't think you can do this that easily with the other library as
you have to use callbacks which add noise to the code.

As an example here is a plunk showing how to do auto-complete for all
the cities in US:
http://plnkr.co/edit/eGG9Kj?p=preview

More info in this SO thread: http://stackoverflow.com/a/15930592/1418796

Hope this helps,
Pawel

Mason Jones

unread,
Apr 15, 2013, 1:16:26 PM4/15/13
to ang...@googlegroups.com
Terrific, thanks very much for the great example -- that really is a very straightforward implementation. I only started working with AngularJS for the first time last week, so I'm still getting used to how to do things. But then when I see them I'm surprised at how easy it can be, if you know the right way. I'll go and play with this example and see how it goes.

Thanks again so much!

-- Mason


Mason Jones

unread,
Apr 15, 2013, 2:39:02 PM4/15/13
to ang...@googlegroups.com
That actually worked great, after I did a little work to figure out some details. Thanks again!

One more follow-up question about using Restangular... Before, I was getting a list of objects to show in the page, and via an "Add" button doing a push() onto the list to show the new item. I found that the result of getList() doesn't provide a push() function. For example, if I do this:

    var company = Restangular.one("companies", company_id);
    $scope.owners = company.getList("owners");

Then of course doing ng-repeat="owner in owners" in the page works just fine. Then I have a field to enter a new one, and I was using $scope.owners.push to add the new one to the list, but I get an error that $scope.owners has no method "push". What approach would you recommend to do this? Of course I could do a whole new getList() call, but that would make a query to the server again, which I hope isn't necessary. I'm hoping there's a simple way, after inserting a new record on the server, to just add the object to $scope.owners...

Thanks again.



Gonto

unread,
Apr 15, 2013, 2:48:33 PM4/15/13
to ang...@googlegroups.com
Hey,

So, actually the list returned is a promise so you cannot add new things to it.

If you're going to add things to the list of owners I recommend doing the following:

company.getList('owners").then(function(owners) {
    $scope.owners = owners;
});

This way, once the promise is finished, you set the list of owners to that scope value.And now you can do push and whatever you want to it.

I'm thinking in implementing this as ngResource of returning actually an empty array first and then filling it out instead of working with promises. Maybe it's going to be easier for everybody.

Pawel Kozlowski

unread,
Apr 15, 2013, 2:50:59 PM4/15/13
to ang...@googlegroups.com
On Mon, Apr 15, 2013 at 8:48 PM, Gonto <gon...@gmail.com> wrote:
> I'm thinking in implementing this as ngResource of returning actually an
> empty array first and then filling it out instead of working with promises.
> Maybe it's going to be easier for everybody.

Well, personally I wouldn't dump promise API support. The $resource
approach is easier on people _at first_ but then the power of promises
is really missing.
This is why support for them was added to $resource recently (in a
non-intuitive way IMO).

Cheers,
Pawel

--
AngularJS book:
http://www.packtpub.com/angularjs-web-application-development/book

Martin Gontovnikas

unread,
Apr 15, 2013, 2:53:36 PM4/15/13
to ang...@googlegroups.com
Hey,

Thanks for the opinion!

I actually did it with promises as I'm used to working with them in Scala so I like them more that the "magic" approach of ngResource. I'm going to give it a thaught and ask more people as well for opinions. Thanks for your opinion!!

@Mason let me know if what I told you worked. It should!

Bests,
Gonto

Mason Jones

unread,
Apr 15, 2013, 4:25:01 PM4/15/13
to ang...@googlegroups.com
Yes, your suggestion worked perfectly -- and of course it makes sense, since I just forgot again that I was working with a promise. I'll get used to that eventually. I'd agree with Pawel, I think, that despite the initial time to get used to working with promises, it is more powerful once past the learning curve.

Thanks as always for the help and the quick response, it's gotten me much farther even just this morning!

-- Mason

Mason Jones

unread,
Apr 15, 2013, 4:26:45 PM4/15/13
to ang...@googlegroups.com
Pawel, I noticed that you're working on the Angular book for Packt, which is available in the early-access version. How far along are you right now? I'll be looking forward to it!

Mason Jones

unread,
Apr 15, 2013, 7:07:35 PM4/15/13
to ang...@googlegroups.com
Almost everything is working really well now thanks to help from you guys. I think there's only one more question I have, about perhaps the best practice for enabling removal of a user from the list. Here's the sequence of events:

- initial list of $scope.owners is loaded via getList():
    company.getList("owners").then(function(owners) {
        $scope.owners = owners;
    });

- then the user can add a new owner by selecting a name from the autocomplete, and it's added to the owners:
    company.post("owners", $scope.userlist[i]).then(function() {
          $scope.owners.push({username:$scope.new_owner_name});
     }

- that works just fine. But I realized that at this point, $scope.owners has two different kinds of objects: the ones from the original getList(), and the one from the push().

- now the user wants to remove the owner they just added. It's not the same type of object, though, so it doesn't have a remove() function to call on it, so it doesn't work.

I can see a few options here, but none of them seem great:

1. Don't use remove(), but instead write some manual $http call that passes enough info to the server to do the DEL operation. But that breaks the nice RESTful API.

2. Use the ID to fetch the object from the server, then call remove() on it. That makes it two trips to the server instead of one, though, which isn't so nice. This could be done either during the Add operation (since the autocomplete just returns the name and ID), or during the delete operation when the user clicks to remove it.

Any recommendations about the best way to do this? Is there another alternative? Any thoughts would be appreciated!

Thanks again.

-- Mason

Martin Gontovnikas

unread,
Apr 15, 2013, 7:13:11 PM4/15/13
to ang...@googlegroups.com
Hey,

When you do the post, do you return the created element? Because if you do, all you'd have to do is:

 company.post("owners", $scope.userlist[i]).then(function(newOwner) {
          $scope.owners.push(newOwner);
     }

And that's it :). That'd work as the new element would have remove method as well :).

Bests,
Gonto 

Mason Jones

unread,
Apr 15, 2013, 7:27:47 PM4/15/13
to ang...@googlegroups.com
That makes altogether too much sense; of course, you're right, and I should have realized I could do that. It is acting a little funny, though. When I try to delete the record referenced by the created element, it calls: DELETE "/api/v1/companies/4" but if I try to delete one of the records from the original getList(), it calls: DELETE "/api/v1/companies/1/owners/3". It's as if it doesn't realize the one returned from the post is a sub-object?

The code for the ones that work: company.getList("owners")
The code for the post: company.post("owners", $scope.userlist[i])

They're both using
    company = Restangular.one("companies", company_id)
So I'd have expected them to behave the same way?

Thank you!

Martin Gontovnikas

unread,
Apr 15, 2013, 7:31:16 PM4/15/13
to ang...@googlegroups.com
Hmm, that's weird.

Please create an issue on the tracker and I'm going to check.

Also, could you please check the value of newOwner.parentResource?

Thanks!

Martin Gontovnikas

unread,
Apr 15, 2013, 7:40:00 PM4/15/13
to ang...@googlegroups.com
Hey,

You're 100% right :). Just found the bug and fixed this.

Please get master's version of Restangular and let me know if this works for you. If it does, I'll tag it.

Thanks,
Gonto

Gonto

unread,
Apr 15, 2013, 8:28:33 PM4/15/13
to ang...@googlegroups.com
I've tested this out and tag it to 0.4.1.

Please let me know if you're still having problems.
To unsubscribe from this group and all its topics, send an email to angular+unsubscribe@googlegroups.com.

Mason Jones

unread,
Apr 15, 2013, 8:45:32 PM4/15/13
to ang...@googlegroups.com
That fixed it, absolutely, thanks! Glad I could help identify a bug while I was getting your advice. ;-)

Everything seems to be working beautifully. I got nice error and warning messages via the AngularUI Bootstrap alerts, too.

Time to write all of this up in a blog post now, I think...

Martin Gontovnikas

unread,
Apr 15, 2013, 8:49:34 PM4/15/13
to ang...@googlegroups.com

Hey,

You're welcome.

If you need any help with the blog post, please contact me.

Bests,
Gonto

--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/QA-irGz4zqM/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.

Gonto

unread,
Apr 19, 2013, 3:21:24 PM4/19/13
to ang...@googlegroups.com
Hey guys,

I've just released v0.5.0 finishing all the intended features for the first version and solving all of Github's issues.

Take a look at this to see all of the neat features:


Bests,
Gonto

Mason Jones

unread,
Apr 19, 2013, 10:41:14 PM4/19/13
to ang...@googlegroups.com
Great, I'll grab that version and see how it goes. I actually have another question about using Restangular, although it's maybe more of a generic question about services in Angular. I want to create a service that encapsulates a model, basically a resource that can be called to fetch a list of items or a specific item, etc. Using Restangular, how would you go about doing that? I guess I'm sort of looking for an example of a best practice for wrapping a model using Restangular; begin pretty new to Angular, it's not immediately obvious to me what the best approach would be.

Thanks for the work!

-- Mason


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.

Ryan Zec

unread,
Apr 20, 2013, 9:26:31 AM4/20/13
to ang...@googlegroups.com
This looks interesting however I have one question, this has been an issue with the regular $resource service and wondering if it still exists with Restangular.

Lets say I have a REST API that returns the following response:

{
  "status":"success",
  "data": {
    "data": [{
      "id":1,
      //more data
    }],
    "meta": {
      "totalRecord":100
    }
  }
}

Is it possible to use Restangular with a REST API that returns data this way as it stands now?

Gonto

unread,
Apr 20, 2013, 5:15:46 PM4/20/13
to ang...@googlegroups.com
That's a very good question.

Thanks to your question, I've added a new section in the FAQ on how you can make this work in Restangular, but of course you can.

Basically, you need to configure 2 fields: responseExtractor (To parse response and return array / object when needed) and listTypeIsArray (to tell inner $resource that getList won't return an array).

Check out:


Let me know if this works for you!

Thanks for the interest and bests,
Gonto

Gonto

unread,
Apr 21, 2013, 6:42:20 PM4/21/13
to ang...@googlegroups.com
Hey Mason,

Regarding your question, I don't think I'd create another service for fetching some element with Restangular. I don't know if it's worth it to encapsulate it even further.

You can just Include Restangular from your controller and start ding Restangular.all("items") and then items.post, item.put, etc. I don't think it's worh encapsulating it. If you don't use Restangular, I agree that you should encapsulate it in a service.

Bests,
Gonto

Ryan Zec

unread,
Apr 21, 2013, 7:30:45 PM4/21/13
to ang...@googlegroups.com
Gonto, on the custom response format, what about handling multiple but simaliar format for example getting users return:

  {
    "status":"success",
    "data": {
      "users": [{
        //data
      }]
    }
  }

but getting posts is formatted like this:

  {
    "status":"success",
    "data": {
      "posts": [{
        //data
      }]
    }
  }

How can this be handled?  Is there a way to get the request information, specifically the url, in the setResponseExtractor() callback?

Martin Gontovnikas

unread,
Apr 21, 2013, 10:56:47 PM4/21/13
to ang...@googlegroups.com
Hey,

For the time being, you cannot handle this case with ResponseExtractor.

Create an issue and I'll work with it. I don't know if it's worth sending the whole URL or just "what" you're getting.

Bests,
Gonto

On Sunday, April 21, 2013 at 11:54 PM, Martin Gontovnikas wrote:

Hey,

For the time being, you cannot handle this case with ResponseExtractor.

Create an issue and I'll work with it. I don't know if it's worth sending the whole URL or just "what" you're getting.

Bests,
Gonto
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/QA-irGz4zqM/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.

clayton collie

unread,
Apr 21, 2013, 11:13:16 PM4/21/13
to ang...@googlegroups.com
Gonto,

i have a question about a common issue i have.
Currently i encapsulate resources into their own services. This may seem like overkill (it is in a lot of cases), but in some cases i prefer to be more "semantic". To that end, i may add methods to the item returned from the service (corresponding to customGet, customPost etc).  

Also, in my domain model (yet another social network), there is a lot of similar actions across resources that i'd like to handle by mixins. For example, we can comment/like/share/follow most entities. Two ways to handle this would be 
1. like i've done, create a service wrapping $resource or Restangular and mixin methods after promises resolve..
2. allow for passing a custom constructor (with the same signature as restangularizeElem/restangularizeCollection) as a per-call option to getList()/one()

Thoughts ?

Mason Jones

unread,
Apr 21, 2013, 11:47:18 PM4/21/13
to ang...@googlegroups.com
I can understand that approach. For the moment, I've ended up going ahead and creating a service for each model. Maybe I'm old-school but I think of it as protection from change -- if I need to change the back-end API for some reason, I can change the access to it in one place, and know that it's okay, instead of tracking down multiple changes in different controllers. I'm using the ui-router package (which is awesome!) so I have some small controllers for various views; using the services helps protect them from change.

Thanks!

Gonto

unread,
Apr 21, 2013, 11:58:07 PM4/21/13
to ang...@googlegroups.com
Hey,

Actually, you can do that in ResponseExtractor. I wanted to make this ResponseExtractor the more generic I could so that you can actually generate your own stuff with each response

ResponseExtractor is a function that receives the response and the operation. It's called after each getList, and one(), so you can do something like this:

function enhanceElem(elem) {
  elem.hey = function() {return "hello"};
  return elem;
}

function enhanceCollection(col) {
  col.hoy = function() {return "hello"};
  return col;
}

function(response, operation) {
  if (operation === "getList") {
    var newResponse = _.map(function(one) {
      return enhanceElem(one);
    });
    return enhanceCollection(newResponse);
  } else {
    return enhanceElem(response);
  }
}

This way, you enhance the collection, you enhance each element and after this, the "restangularizeElement" os "restangularizeCollection" is called and other methods are added.

Hope this works for you!

If you need to configure this "enhancement" based on URL as well, please go ahead and create the issue on github and I'll get onto it tomorrow if I can :).

Gonto

unread,
Apr 22, 2013, 12:29:12 AM4/22/13
to ang...@googlegroups.com
That's awesome :). I've not tried ui-router yet, but I might give it a try.

Please let me know if you need help with anything else!

Ryan Zec

unread,
Apr 22, 2013, 8:58:02 AM4/22/13
to ang...@googlegroups.com
Gonto,

Martin Gontovnikas

unread,
Apr 22, 2013, 11:14:01 AM4/22/13
to ang...@googlegroups.com
Thanks!! I'll try to work on it today
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/QA-irGz4zqM/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.

Mason Jones

unread,
Apr 22, 2013, 7:32:56 PM4/22/13
to ang...@googlegroups.com
Hi Gonto, I have another probably simple question, but I'm not finding an example in the Restangular docs. Let's say I have companies, and then people in the companies. I have a REST API that will take a GET of "/companies/1/people/123". If I have the IDs of the company and the person, what's the right way to do that GET from Restangular?

I thought it would probably be something like this:

      var company = Restangular.one("companies", company_id);
      var person = company.one("people", person_id);
      return person.get();

Or maybe:

      var company = Restangular.one("companies", company_id);
      var person = company.get("people", person_id);

That last one sort of works but generates a GET of "/companies/123", using the person_id as the company_id. Which does sort of make sense, of course. So what's the proper way to do this? I looked through the examples in the README but I didn't find this particular case.

Thanks.

Gonto

unread,
Apr 22, 2013, 11:26:54 PM4/22/13
to ang...@googlegroups.com
Hey,

What you want to do isn't possible right now.

The idea of Restangular is that you can "navigate" through the tree of your Rest API, so, what you'd do is something like this (at least in my mind).

var company = Restangular.one("companies", 1);

company.get().then(function(comp) {
  // Here you have company information
  $scope.company = comp;
});

Once you have and show company information, some other part now needs actually the people information. So the idea is that you'd have this $scope.company object sent to where you need to get the person (For example using ui-router you can inherit state or something like this :)).

Then, from your child controller, once you receive this $scope.company, all you'd do is:

$scope.company.getList("people").then(function(people) {
  // Here you'd display the people needed and then show the right person.
})

However, now that I think of something that might be cool to add is a "getChild" method:

company.getChild("people", 123) besides the getList. I think it might be cool to add this :), 

What do you think?

Bests,
Gonto

Gonto

unread,
Apr 23, 2013, 4:14:53 PM4/23/13
to ang...@googlegroups.com
Hey,

I ended up adding URL Building and Tree Navigation instead of this getCihld. I think it's more generic, and it's quite useful for everything :).


You can use this from version 0.5.3 of Restangular.

Basically, you can do the following:

var restangualrSpaces = Restangular.one("accounts",123).one("buildings", 456).all("spaces");

// This will do ONE get to /accounts/123/buildings/456/spaces
restangularSpaces.getList()

// This will do ONE get to /accounts/123/buildings/456/spaces/789
Restangular.one("accounts", 123).one("buildings", 456).one("spaces", 789).get()

// POST /accounts/123/buildings/456/spaces
Restangular.one("accounts", 123).one("buildings", 456).all("spaces").post({name: "New Space"});
I hope this works for you :). You can check the tests for this functionality as well :)

Bests,
Gonto

Gonto

unread,
Apr 23, 2013, 6:10:06 PM4/23/13
to ang...@googlegroups.com


On Monday, April 22, 2013 8:32:56 PM UTC-3, Mason Jones wrote:
Hi Gonto, I have another probably simple question, but I'm not finding an example in the Restangular docs. Let's say I have companies, and then people in the companies. I have a REST API that will take a GET of "/companies/1/people/123". If I have the IDs of the company and the person, what's the right way to do that GET from Restangular?

I thought it would probably be something like this:

      var company = Restangular.one("companies", company_id);
      var person = company.one("people", person_id);
      return person.get();
This is the one that's going to work with new implementation :) 

Mason Jones

unread,
Apr 23, 2013, 7:10:23 PM4/23/13
to ang...@googlegroups.com
Excellent -- that does the job perfectly! One nice line in my factory now and it does exactly what I needed. Thanks for the super-quick work on that. I'll let you know if I run into any bugs on the way.

Gonto

unread,
Apr 23, 2013, 7:59:28 PM4/23/13
to ang...@googlegroups.com
Thanks for the feedback! That's what is making this better and better :)

Gonto

unread,
Apr 26, 2013, 9:29:23 PM4/26/13
to ang...@googlegroups.com
Hey guys,

Just pushed a new version of Restangular.

Now you can create your own Restangular methods to use later :)


//In your app configuration (config method)
RestangularProvider.setOnElemRestangularized(function(elem, isCollection, route) {
    if (!isCollection && route === "buildings") {
        // This will add a method called evaluate that will do a get to path evaluate with NO default
        // query params and with some default header
        // signature is (name, operation, path, params, headers, elementToPost)
        elem.addRestangularMethod('evaluate', 'get', 'evaluate', undefined, {'myHeader': 'value'});
    }
    return elem;
})

// Then, later in your code you can do the following:

//GET to /buildings/123/evaluate?myParam=param with headers myHeader: value
//Signature for this "custom created" methods is (params, headers, elem)
// If something is set to any of this variables, the default set in the method creation will be overrided
// If nothing is set, then the defaults are sent
building.evaluate({myParam: 'param'});

//GET to /buildings/123/evaluate?myParam=param with headers myHeader: specialHeaderCase
building.evaluate({myParam: 'param'}, {'myHeader': 'specialHeaderCase'});

Thanks for using it !!!

Gonto

unread,
May 3, 2013, 2:20:51 AM5/3/13
to ang...@googlegroups.com
Hey guys,

Just added a BUNCH of new features.

Check them out here:


I think you're going to find some of them very usefull. An example is Transformed promises :)

Psi

unread,
May 12, 2013, 3:56:35 PM5/12/13
to ang...@googlegroups.com
Hey Guys,
im very new to Angular and would ask if this is the right way using it with Restangular:

// myController:
var User = Restangular.one('users', $routeParams.id);

User.get().then(function(tmp){
	$scope.User = tmp;
});

$scope.save = function(){
	$.extend(User, $scope.User);
	User.put();
};

any suggestions? Or is this the way ive to do it?

Martin Gontovnikas

unread,
May 12, 2013, 4:05:22 PM5/12/13
to ang...@googlegroups.com
Hey,

I'd recommend having scope variables in lower case per convention.

Besides that, in the save, you could do

$scope.user.put() and that's it.

Bests,
Gonto
--

Psi

unread,
May 12, 2013, 4:21:40 PM5/12/13
to ang...@googlegroups.com
Oh thanks! I thought the tmp in the then() function was only the payload and not really a Restangular object.
Why do i have to resolve the promise by myself and cant do a

$scope.User = Restangular.one('users', $routeParams.id).get();

(more precisely, why cant i alter the values)

Greets,
  Psi

Pradeep Dantuluri

unread,
May 12, 2013, 4:26:59 PM5/12/13
to ang...@googlegroups.com
Hi Gonto,

How hard is it to use restangular when I get only XML from the server. Sorry for asking a very broad question, but I wanted your views on this before I dig deep and extend restangular. 

On the outset I found xml data returned from the server doesn't play well with restangular. Can I somehow add a middle-ware which can handle the data before restangular takes over? 'responseInterceptor' doesn't do the job.

cheers
--
Pradeep


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.

Martin Gontovnikas

unread,
May 12, 2013, 4:49:56 PM5/12/13
to ang...@googlegroups.com
Hey,

I don't really know how XML work with AngularJS. I've never used it. But if it works with $resource, it must work with Restangular. Also, in the property defaultHttpFields you can set whatever transformRequest you want as in $http.

I don't know if this answers your question but I haven't really used XML.

Bests,
Gonto

Julia Jacobs

unread,
Jul 13, 2013, 4:04:49 PM7/13/13
to ang...@googlegroups.com, gon...@gmail.com
Do you have an example of using AngularStrap's TypeAhead with Restangular?

I tried:

 $scope.typeaheadFn = function(query, callback) {
      var regions = Restangular.one('search', query).get().then(function() {
        console.log("All ok");
      }, function(response) {
        console.log("Error with status code", response.status);
      });

      callback(regions);
  }

but I'm not really getting anywhere.

Thanks!

On Saturday, April 13, 2013 12:23:43 PM UTC-5, Martin Gontovnikas wrote:
Hey,

You're absolutely right.

The TypeAhead library must be able to receive data async, as that's one of the main features of it. Check out AngularStrap, I've used it with Restangular and it works great :).

  1. <!-- Async function defined in your controller -->
  2. $scope.typeaheadFn = function(query, callback) {
  3. $http.get('/stations/autocomplete?term='+query).success(function(stations) {
  4. callback(stations); // This will automatically open the popup with retrieved results
  5. });

Bests,
Gonto

On Saturday, April 13, 2013 2:55:42 AM UTC-3, Mason Jones wrote:
Actually, never mind my follow-up question here; obviously it needs to be able to handle the delayed data, it's just not doing it properly right now...


On Friday, April 12, 2013 10:44:22 PM UTC-7, Mason Jones wrote:
Thanks for your quick response. Yes, this does make sense, actually; I hadn't quite thought it through that even long after the data was loaded, in a separate click-driven event, it still needs to use then().

Here's a follow-up question, as I'm working on using Restangular in an autocomplete function as well... I'm having the trouble that when the user types something, it's not expected to return without the data:

$scope.doGetAutocomplete = function (request, response) {
    var allUsers = Restangular.all('users.json');
    allUsers.getList('', {query: $scope.ownerSearch}).then(function(data) {
      response(data.suggestions);
    });
};

This "works" except that the doGetAutocomplete() function returns immediately, which blows up. What's the best way to block the return until the then() function finishes?

Thanks again, I appreciate the tips.


Gonto

unread,
Aug 5, 2013, 3:19:30 AM8/5/13
to ang...@googlegroups.com, gon...@gmail.com
Hey,

I don't have an example, but you should call the callback on the success of getting what's need so do this instead:

 $scope.typeaheadFn = function(query, callback) {
      Restangular.one('search', query).getList().then(function(regions) {
        console.log("All ok");
            callback(regions);
      }, function(response) {
        console.log("Error with status code", response.status);
      });
  }

As you were using it before, you were actually calling the callback with a promise instead of a list.
Reply all
Reply to author
Forward
0 new messages