Struggling to transition an ngResource angular service to plain Vanilla JavaScript

We are in the process of transitioning our website from old AngularJS to Vue.js. The first step involves updating the services used across the site, which heavily depend on ngResource, and converting them into vanilla JavaScript code that can be accessed by Vue.

The main challenge lies in the fact that, aside from making API calls using ngResource, these services also extend the returning object via prototype. While I can replicate the API behavior of the ngResource service using the module pattern in regular JavaScript, I'm unsure how to set it up so that it also supports the prototype extensions applied to the returning object (whether it's a single object or an array).

For instance, one of our existing services currently looks 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;
        }
    ]);

It's important to note that this service makes a call named query but also enhances the returning object with a new function called getPicUrl.

I have created a JavaScript 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 component functions correctly, but I am uncertain about replicating what ngResource does, namely returning a resource with the prototype extensions included.

Any guidance on this matter would be greatly appreciated. Thank you!

Answer №1

As mentioned in my previous responses to @Igor Moraru, the process of replacing a significant portion of your code base with ngResource capabilities is quite complex. However, focusing on the specific scenario outlined in your query, it is essential to first gain a better understanding of vanilla JS.

The discrepancy in the existence of a prototype property within the Portfolio object when returned from $resource(), as opposed to when created using an object literal, can be attributed to the nature of JavaScript functions and classes. The function returned by $resource() serves as a class, hence automatically possessing a prototype property.

In JavaScript, functions and classes essentially perform the same functionality with differing intentions. In this instance, the function from $resource() is intended for class usage, thereby enabling the replication of class-specific features like the static query method and non-static 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 => {
                return res.data.map(e => new this(e));
            });
        }
        
        getPicUrl() {
            return this.ImgBasePath + this.ImgUrl;   
        }
    }

    return Portfolio;
})();

However, this may not suffice for complete migration or refactoring of your application, especially if extensive utilization of ngResource exists throughout your codebase beyond this class. Static methods such as get, post, alongside corresponding instance methods, also need consideration.

You may consider three options:

  • Tailor the existing class to better suit your requirements and subsequently update all instances within your application to align with the modified class structure.
  • Analyze and potentially modify the source code of ngResource to eliminate AngularJS dependency, possibly utilizing existing libraries that offer similar functionalities.
  • Maintain AngularJS within your app alongside Vue solely for essential functions like $http and $resource. While feasible, this approach may introduce additional complexities and overhead.

Answer №2

Instances of objects do not directly expose the prototype property. Instead, you can access it using:

  object.__proto__ // this method is not recommended, or alternatively
  Object.getPrototypeOf(object)

Object.getPrototypeOf() returns the object's prototype object, which can be used to add new properties.

Object.getPrototypeOf(Portfolio).getPicUrl = function () {
     return this.ImgBasePath + this.ImgUrl;
}

Note: It is possible to access the prototype of Function() by using Function.prototype.

UPDATE: To avoid the mentioned issue by @user3781737, make sure that your Portfolio is a new object created from the global JavaScript object.

 var Portfolio = Object.create({
      query: function() {
        return axios.get(baseapipath + "portfolios/");
      }
    });

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieve JSON Data Using Angular in a Wordpress Environment

I need assistance with displaying a JSON Array in <li>'s within a Wordpress Template. Here is the specific JSON file: I am completely unfamiliar with how to achieve this. This is the HTML code I have: <div ng-app="appExtern" ng- ...

Display a confirmation modal before triggering $routeChangeStart in AngularJs, similar to the window.onbeforeunload event

When a user chooses to stay on the page as the route starts to change, the original route remains intact but the form directives are reloaded. This results in the loss of all checkbox and input values, resetting them to their defaults. If a user closes th ...

Attempting to transfer a Vue component from one component to another, without directly involving the App.vue file

Hello everyone, I recently created a component called Hamburger.vue in my components directory. I then attempted to import this hamburger component into my Header.vue file to avoid unnecessary code repetition. For reference, here is the link to the playg ...

Tips for utilizing Mongoose populate with a subdocument within the identical model?

This is the model for my latest project. const customHeaderSchema = new Schema({ header: { type: String, required: true, }, }); const customFeatureSchema = new Schema({ title: { type: String, required: true, ...

The ajax request does not support this method (the keydown event is only active during debugging)

I've encountered a strange issue with an AJAX request. The server-side code in app.py: #### app.py from flask import Flask, request, render_template app = Flask(__name__) app.debug = True @app.route("/myajax", methods=['GET', ...

My code gets disrupted when I switch between ids and classes

I'm currently learning about javascript and jquery, attempting to implement various scripts. I successfully executed the following script: jQuery(document).ready(function($) { var scroll_start = 0; var startchange = $('#homepage-header' ...

Converting JavaScript code from Jade into EJS framework

I am currently working on converting code from Jade to EJS and could use some assistance. I have started the translation process, but I'm not entirely confident in my approach. Additionally, I find the syntax used in EJS to be confusing compared to tr ...

How to transfer data from an HTML form to PHP using AJAX

I've encountered an issue while working on a simple application that consists of one HTML file communicating with a PHP page using AJAX. Take a look at my index.html below: <!DOCTYPE html> <html><head> <meta charset="utf-8"> & ...

Incorporating 'unsafe-eval' into the current chrome extension

I have a popular Chrome extension available in the Chrome store that is used by numerous people. Recently, I integrated alasql which requires the use of the eval function, leading me to need to enable unsafe-eval in the content_security_policy. I'm cu ...

A guide on implementing a jQuery click function on ng-click in an AngularJS application

Currently, I am developing a mobile app and utilizing MDL for the app's UI along with Angular JS. The theme I purchased from ThemeForest is called "FAB." My goal is to display data from the server using API's and showcase all the products that ar ...

Encountered a connection error in the Spring Boot application: net::ERR_CONNECTION_REF

Currently working on a school project developing a Spring Boot application using Restful. The application runs smoothly locally, but when deployed to AWS, I am encountering an "net::ERR_CONNECTION_REFUSED" error for all my GET and POST requests sent to the ...

How can dataTables in VueJS be reloaded following an addition or edit?

I'm interested in implementing a similar approach for loading data from a database via an API. Initially, the dataTables load successfully. However, when a new record is added, I need to reload the dataTables to display the new record. Below is the HT ...

Javascript problem: Understanding the .children method and how to use it

I have implemented a basic JavaScript/CSS code to show a tooltip/enlarged photo feature. You can visit the actual page here. The thumbnail images are located on the right-hand side. The issue I am facing is that when using the mouseenter function, the to ...

Upon submission, the form is processed and 'false' is returned

Does anyone know how I can use ajax to save form data? I am encountering an issue where the page refreshes when all entries are correct. If I input any incorrect data and submit, it displays an error. However, if I then fill in all correct information, it ...

Node: Sending JSON Values in a POST Request

I am currently working with the index.js file below: var Lob = require('lob')('test_6afa806011ecd05b39535093f7e57757695'); var residence = require('./addresses.json'); console.log(residence.residence.length); for (i = 0; i ...

Having trouble getting the JavaScript function to run when clicking a button inside a div or form?

Hey there, so I've got this scenario where I have a button nestled within a div. Take a look at the HTML snippet below: <div class="row"> <button type="button" id="submit">Send</button> </div> Prior to this button, there ...

Using the jquery plugin Sidr in Rails: A complete guide

I've been attempting to integrate the jQuery sidr plugin into my Rails project on Codecademy, but unfortunately, it's not functioning as expected. To view the page, simply click here: If you notice, the menu icon at the top left takes some time ...

IE11 blocking .click() function with access denied message

When attempting to trigger an auto click on the URL by invoking a .click() on an anchor tag, everything works as expected in most browsers except for Internet Explorer v11. Any assistance would be greatly appreciated. var strContent = "a,b,c\n1,2,3& ...

Renew the id_token in the front-end: Angular 4

I am currently utilizing the ng2-adal npm library to create id_token and access_token. As the id_token is valid for 30 minutes and the access_token for 60 minutes, my goal is to automatically refresh the id_token every 20 minutes in the background. One pot ...

AngularJS directive that rounds numbers to two decimal places

I am looking to develop a custom directive that rounds off two-digit values after the decimal point. For instance: 10.456456 will be rounded to 10.46 10.3633 will be rounded to 10.34 Here is my current attempt at the directive, but it seems to be ineffe ...