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
Portfolioobject have aprototypeproperty 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 aprototypeproperty 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 staticquerymethod and the non-static (i.e., on the prototype)getPicUrlmethod: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
$resourcealso has static methods such asget,post, etc., as well as corresponding instance methods such as$get,$post, and so on. In addition, theconstructorI'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 thegetPicUrlmethod.So I think you have three options:
$httpand$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: