Lodash and AngularJS ngResource promise don't work well - javascript

I use lodash within my AngularJs app and it works well for local collections/arrays.
When I try to use it like so it doesn't work:
vm.colorsSizes = _.uniq(commonData.stock, 'colorName');
where commonData.stock is an array that resolves from an ngResource call.
angular
.module("common.services")
.factory("commonData",
["stockResource",
commonData]);
function commonData(stockResource) {
return {
stock: stockResource.query()
}
}
Why this happens and how can I fix it?

It sounds like you are trying to access it when it hasn't resolved yet and it's still empty. Give this a whirl:
commonData.stock.$promise.then(function () {
vm.colorSizes = _.uniq(commonData.stock, 'colorName');
});

Related

How to access javascript object inside another object

enter code hereHow to access objects in Javascript
This is the Object trying to Access
This is the Code
Its returning 'UNDEFINED' why?
It may be silly. please help me im new.
CODE :
app.controller("myCtrl", function($scope,Restangular) {
Restangular.setBaseUrl('http://localhost:8080/StrutsREST/api');
var arr=Restangular.all('interfaces').doGET();
var obj=arr.$object;
console.log(obj.A1);
});
As you are doing API call which is async you need to handle it as Promise by using .then statement
Restangular.all('interfaces').getList().then(function(data) {
console.log(data.A1);
})

Stuck converting ngResource angular service to Vanilla JS

We are migrating our site from old angularjs to using Vuejs.
Step one is to modify our services used throughout the site which all rely heavily on ngResource and convert them into vanilla js code that can be called by Vue.
The challenge is that in addition to making API calls using ngResource they also extending the returning object via prototype.
While using a the module pattern in regular javascript I can mimick the API behaviour of the ngResource service. But I am not clear how to set this up so that it can also support the prototype extensions that are being applied to the returning object (whether a single object or an array).
For example one of our current services might look like this
"use strict";
angular.module("myApp")
.factory("PortfolioService",
[
"$resource", "$rootScope", "$http",
function($resource,
$rootScope,
$http) {
var Portfolio = $resource("services/portfolios/:Uid",
{
'_': function() { return Date.now() }
}, {
'query': {
method: "GET",
url: "services/portfolios/",
transformResponse: $http.defaults.transformResponse.concat([
function (data) { return data.Data; }
])
}
});
Portfolio.prototype.getPicUrl= function() {
return this.ImgBasePath + this.ImgUrl;
};
return Portfolio;
}
]);
Note: that it mames a service call called query but also extends the returning object with a new function called getPicUrl.
I have created a JS equivalent that looks like this
const vPortfolioService = (() => {
var baseapipath = "http://localhost:8080/services/";
var Portfolio = {
query: function() {
return axios.get(baseapipath + "portfolios/");
}
};
Portfolio.prototype.getPicUrl= function () {
return this.ImgBasePath + this.ImgUrl;
}
return Portfolio;
})();
The service part works fine but I dont know how to do what ngResource seems to do which is to return a resource from the API which includes the prototype extensions.
Any advice would be appreciated.
Thanks
As I mentioned in my replies to #Igor Moraru, depending on how much of your code base you're replacing, and how much of that existing code base made use of the full capabilities of ngResource, this is not a trivial thing to do. But just focusing on the specific example in your question, you need to understand some vanilla JS a bit more first.
Why does the Portfolio object have a prototype property when it's returned from $resource(), but not when it's created via your object literal? Easy: The object returned by $resource() is a function, which in turn also means it's a class, and those have a prototype property automatically.
In JavaScript, regular functions and classes are the same thing. The only difference is intent. In this case, the function returned by $resource() is intended to be used as a class, and it's easy to replicate certain aspects of that class such as the static query method and the non-static (i.e., on the prototype) getPicUrl method:
const vPortfolioService = (() => {
var baseapipath = "http://localhost:8080/services/";
class Portfolio {
constructor(params) {
Object.assign(this, params);
}
static query() {
return axios.get(baseapipath + "portfolios/").then(res => {
// this convert the objects into an array of Portfolio instances
// you probably want to check if the response is valid before doing this...
return res.data.map(e => new this(e));
});
}
getPicUrl() {
return this.ImgBasePath + this.ImgUrl;
}
}
return Portfolio;
})();
But the problem is, this probably isn't enough. If you're migrating/refactoring an entire application, then you have to be certain of every instance in which your application uses ngResource, and based on your question, I'm fairly certain you've used it more than this class would allow.
For example, every class created by $resource also has static methods such as get, post, etc., as well as corresponding instance methods such as $get, $post, and so on. In addition, the constructor I've provided for the class is just a very lazy stop-gap to allow you to create an instance with arbitrary properties, such as the properties referenced by the getPicUrl method.
So I think you have three options:
Continue playing with the above class to fit something closer to what you need, and then edit every place in your application where your code relies on the Portfolio Service so that it now reflects this new, more limited class. This is probably your best option, especially if your application isn't that big and you don't have to worry about someone else's code not working
Analyze the source code for ngResource, rip it out, and modify it so it doesn't need AngularJS to work. Perhaps someone has already done this and made it available as a library? Kind of a long shot I'd guess, but it may work.
Keep AngularJS in your application, alongside Vue, but only use it to grab the essentials like $http and $resource. An example implementation is below, but this is probably the worst option. There's additional overhead by bootstrapping pieces of angular, and tbh it probably needs to bootstrap other pieces I haven't thought of... but it's neat I guess lol:
const vPortfolioService = (() => {
var inj = angular.injector(["ng", "ngResource"]);
var $http = inj.get("$http"), $resource = inj.get("$resource");
var Portfolio = $resource("services/portfolios/:Uid",
{
'_': function () { return Date.now() }
}, {
'query': {
method: "GET",
url: "services/portfolios/",
transformResponse: $http.defaults.transformResponse.concat([
function (data) { return data.Data; }
])
}
});
Portfolio.prototype.getPicUrl = function () {
return this.ImgBasePath + this.ImgUrl;
};
return Portfolio;
})();
Object instances does not exposes prototype property. Instead you can access it by using:
object.__proto__ // not recommended, or better
Object.getPrototypeOf(object)
Object.getPrototypeOf() return object's prototype object, which you can use to assign new properties.
Object.getPrototypeOf(Portfolio).getPicUrl= function () {
return this.ImgBasePath + this.ImgUrl;
}
Note: You still can, though, access the prototype of Function() by doing Function.prototype.
UPDATE: Your Portfolio should be a new object, created from the global javascript object, to avoid the issue that #user3781737 has mentioned.
var Portfolio = Object.create({
query: function() {
return axios.get(baseapipath + "portfolios/");
}
});

Getting a value from a AngularJS Promise in MeanJS

I'm playing around with MeanJS recently and I ran into an issue that I'm not well versed in so I'm hoping someone can help here.
I have a angular controller that sets it scope like this:
// Find existing Topic
$scope.findOne = function() {
$scope.topic = Topics.get({
topicId: $stateParams.topicId
});
};
I this sets the topic in the $scope. However, I also need to get a value off of the topic as well. Lets assume it is a date such as createdAt. I need to get this value and then perform another operation on it in order to set another scope value. The problem is, the $scope.topic object is an Angular promise. How can I get the value createdAt (which is a Date) off of that promise?
You can use promise callback.
$scope.findOne = function() {
$scope.topic = Topics.get({
topicId: $stateParams.topicId
});
$scope.topic.$promise.then(function(data) {
// access data.createdAt here
});
};
Its actual also depends on that where you want to use this. So if you want to use this in the view, you can write directly as:
<span> Created at: {{topic.createdAt}}</span>
Angular will autoupdate that scope variable when data is loaded.

Restangular Multiple IDs in GET

I'm looking at switching from resource to restangular in my AngularJS app. I like the new model, but I have one problem. I can't figure out how to make this API call:
http://localhost:8000/api/entity/groups/1,2,3,4/events
I have code like this:
var GroupService = ['Restangular', function (Restangular) {
var restAngular = Restangular.withConfig(function (Configurer) {
Configurer.setBaseUrl('/api/entity');
});
return {
getEvents: function (groupIds) {
return restAngular.all('groups', groupsIds).getList('events');
}
}
}];
Is there a way to ask for a set of groups (more than one and not all of them) and then get all events for any of those groups?
Use several method of Restangular
Restangular.several('accounts', 1234, 123, 12345).customGETLIST('events');
P.S.: I think this might be a bug of Restangular that .getList('events') is not working.

How does AngularJS return a value from async call?

Watch this video,
https://www.youtube.com/watch?v=IRelx4-ISbs
You'll find that the code has a line wrote this:
$scope.twitterResult = $scope.twitter.get({q:$scope.searchTerm});
This is a litter quirk:
the 'get' method of 'twitter' is obviously a async function, how does it return a value to $scope.twitterResult???
jsFiddle(Can't work cause the twitter API has changed):
http://jsfiddle.net/johnlindquist/qmNvq/
This code $scope.twitter.get({q:$scope.searchTerm}); return defer object. Angular view arranged so that view will be update when defer object resolve. It's just a convenience.
$scope.twitterResult = $scope.twitter.get({q:$scope.searchTerm});
Your code is good for only angular binding.
But if you need to get data on run time, you need to write this below format.
If $scope.twitter is a URL,Then write it
$http.get($scope.twitter, {q:$scope.searchTerm}).success(function (response) {
$scope.twitterResult=response;
}
$http is must defined in contoller

Categories

Resources