Automatically rehydrate an instance using Angular and JavaScript

REVISION

Special thanks to Shaun Scovill for providing an elegant solution using lodash

    // Creating an instance and injecting server object - within the ChartService implementation below
    var chart = new Chart(serverChartObject);

   // Replacing the Chart factory with the following code to simplify the object constructor creation using the server object and initializing it!

    Chart.$inject = [];
    function Chart() {

        return function(serverChartObject) {
            var keys = ['app_id', 'article_id', 'section_id', 'data', 'headline', 'legend', 'source', 'source_url', 'subtitle', 'summary', 'width', 'height'];
            _.assign(this, _.pick(serverChartObject, keys));
        };
    }

DEVELOPER TOOLS

Angular : 1.4.7 RequireJS: 2.12 Laravel 5.1.x Lodash 3.10.1

QUERY:

I'm exploring better approaches to automating hydration and protection of an AngularJS / JavaScript object instance.

SCENARIO

In this scenario, I retrieve a collection of chart objects from Laravel 5.1 backend (or any other backend returning a JSON object). A service module called ChartService is used to parse this data into JavaScript Chart objects.

GOAL

I aim to achieve the following with minimal code:

  1. Create a Chart object instance
  2. Hydrate the JS object with server chart data
  3. Protect the object data properties OR a subset such as article, app_id, section_id and data

INITIAL APPROACH

I initially employed

Object.defineProperty(Chart, 'app_id', { value: 1 });
along with protected approaches mentioned above. However, if I execute chart.app_id = 3, it overwrites the app_id. On the other hand, Object.freeze(chart) prevents all properties from being altered or modified.

CURRENT STRATEGY

NOTE: Some code has been omitted for brevity, apologies if context was compromised.

define([
    'angular',
    'lodash'

], function(angular, _) {
    'use strict';

    ChartService.$inject = ['$http', '$q', '$sce', '$rootScope', 'api', 'Chart'];
    function ChartService($http, $q, $sce, $rootScope, api, Chart) {

        var chartService = {
            charts: [],
            // NOTE : call parse from external source
            parseCharts: function(items) {
                var self = this,
                    chart,
                    articleId = null,
                    sectionId = null;

                // NOTE : items are a collection of chart objects from Laravel
                if (angular.isDefined(items) && Object.keys(items).length > 0) {
                    // NOTE: c = chart server object
                    _.each(items, function(c,k) {
                        // factory Chart instance
                        chart = new Chart();
                        // NOTE : hydrate chart instance with c (server chart object data)
                        chart = hydrateInstance(c, chart);
                        // freeze object
                        Object.freeze(chart);
                    })
                }
            }
        };

        function hydrateInstance(obj, instance) {
            for (var prop in obj) {
                if (obj.hasOwnProperty(prop) && instance.hasOwnProperty(prop)) {
                    instance[prop] = obj[prop]
                }
            }
            return instance;
        }

        return chartService;
    }


    Chart.$inject = [];
    function Chart() {
        /**
         * Constructor, with class name
         */
        function Chart(app_id, article_id, section_id, data, headline, legend, source, source_url, subtitle, summary, width, height) {

            var self = this;
            self.app_id = app_id;
            self.article_id = article_id;
            self.section_id = section_id;
            self.data = data;
            self.headline = headline;
            self.legend = legend;
            self.source = source;
            self.source_url = source_url;
            self.subtitle = subtitle;
            self.summary = summary;
            self.width = width;
            self.height = height;
        }
        // removed rest of object / prototype properties for brevity sake

        return Chart;
    }


    return angular.module('cmo.content.charts', [

        ])
        // remove config for brevity
        .factory('Chart', Chart)
        .service('ChartService', ChartService);

});

Answer №1

To make your Chart constructor more concise, consider utilizing a combination of lodash functions such as assign and pick. Here's an example:

function Chart() {
    return function(config) {
        var properties = ['app_id', 'article_id', 'section_id', 'data', 'headline', 'legend', 'source', 'source_url', 'subtitle', 'summary', 'width', 'height'];
        _.assign(this, _.pick(config, properties));
    }
}

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

Could the absence of an external style sheet for CSS be hindering the execution of my code?

A generous Stack Overflow user provided me with the code you see here and their JSFiddle can be accessed at http://jsfiddle.net/f18513hw/. The code functions properly in JSFiddle. I copied and pasted the code into my Textpad, saved it in my htdocs folder o ...

What is the best way to add a separator in a b-dropdown menu once the options have been loaded using Vue?

Here is the code snippet for my dropdown element: <b-dropdown id="SchemaDropdown" name="SchemaDropdown" variant="form-control" class="" style="width: 100%" ...

Storing AngularJS Data on Server

Recently delving into AngularJS and starting to find my way around it, I must say I'm quite enjoying the experience. Transitioning from the Java/JSP realm has definitely posed a learning curve for me! Currently, my focus is on configuring logging to ...

Ensure the correct file extension is chosen when selecting a file for the 'file_field' and display any error messages using Ruby on Rails

I am currently using Ruby on Rails 3 and Prototype, and I need to be able to check the file extension when a file is selected with file_field. I only want to allow files with extensions of .doc or .pdf, any other extensions should display an error. In my ...

Steps to troubleshoot the TypeError: cv.Mat is not a constructor in opencv.js issue

Encountering a problem while trying to use opencv.js for detecting aruco markers from my camera. Each time I attempt to utilize the method let image = new cv.imread('img'); An error keeps popping up: TypeError: cv.Mat is not a constructor ...

Exploring the functionality of Protractor testing in combination with Angular 2, focusing

I am currently developing an Angular 2 application and I require some information regarding unit testing with Protractor. Previously, in Angular 1, we were able to check for things like: element(by.css('[ng-click="myFunction()"]')) in our test ...

Guide on sending a personalized email to multiple recipients using office.js

Is it possible to send individual emails when using office.js in Outlook for mail delivery? For instance, if there are 5 recipients, can the email be sent so that each recipient only sees their own email and not others'? This is unrelated to BCC fun ...

Navigating Redirects using axios in the Browser

Is there a way to work with redirects in axios to capture the redirected URL in the browser when making an API call? I am looking to retrieve the redirected URL through a GET request. ...

I am having trouble scrolling through the main content when the side-drawer is open. How can I fix this issue?

When the sidebar is opened, I am facing issues with the main content scroll and certain fields such as select options and search bar not functioning properly. I have included the main content in the routes from which it is being loaded. However, the scroll ...

Replacing a string in a textarea using Jquery

Trying to dynamically replace a string value in a textarea while typing into a textbox using jQuery. Utilizing the keypress event for this functionality. Any ideas on what could be causing issues with this example? <input type="text" id="textbox" /> ...

What could be causing the Multer error in my Express.js application when attempting to upload a file for the second time, even though the first time was successful?

Whenever I try to upload a single file, the code works flawlessly. However, if I attempt to upload another file, I encounter the following Multer error: Error code: 'LIMIT_UNEXPECTED_FILE', field: 'myFile', storageErrors: [] To succes ...

Maintain the state of various panels on page load with the Bootstrap Accordion feature

I have implemented a Bootstrap accordion on my form page which allows users to open multiple panels simultaneously. Upon submitting the form, I want to preserve the state of any open Bootstrap accordion panels. To achieve this, I utilized code from stack ...

Utilize React's Context Provider to centrally manage all state while incorporating async calls

I am currently exploring more refined methods to establish a provider/consumer setup in which an asynchronous call is initiated from the provider, but the consumer does not need to handle state management. Within my context provider, I am fetching data to ...

Can you explain the variance between using querySelector() and getElementById/getElementsByClassName/getElementsByTagName()?

I'm confused about the distinction between using querySelector() and getElementById(). From what I understand, querySelector is able to retrieve an element using any selector, giving it more flexibility. Are there additional contrasts between the two ...

Implementing non-blocking asynchronous object return in a node.js function

Struggling with a function that accesses data from a JSON file and queries it for a specific key. Unfortunately, the return function seems to be executing before the query can find the key. Even after querying and attempting to return the variable queryre ...

I keep getting an error saying "wallet.connect() is not a function," even though it was working perfectly just a few

`` I'm currently working on the FCC solidity course and I've reached the 7:45 mark. Everything was running smoothly until I encrypted the RPC url, private key, and password. Now, when trying to connect my wallet variable to the provider variable ...

Dynamic loading of JavaScript/HTML content using jQuery Mobile and PhoneGap

I am currently in the process of building a mobile app using Dreamweaver CS6 (with PhoneGap), along with jQuery Mobile and JavaScript. This app aims to gather user-inputted form data, convert it into a JSON object, and send it to a python web service. The ...

Unable to log out when the button is clicked

I am having trouble figuring out why I can't log out when clicking the button. I have a logout button in my header (navigation). My experience with React is limited. Within my project folder, I have a Store directory which contains an Auth-context f ...

Editing DOM elements within Angular JS using Greasemonkey extension

I have been developing a Greasemonkey script to enhance the performance of a vendor's angularJS tool by automating certain processes. One major obstacle I am encountering is that the element I need to interact with is not yet loaded in the DOM when m ...

Using AngularJS to bind a dictionary to an ng-repeat function

Hello everyone! I have a dictionary with keys and lists of objects returned from my controller. I want to bind this data to a table or another element using the ng-repeat directive. This is how the data looks when returned from the controller: https://i.s ...