How can one effectively separate logic in AngularJS for optimal performance?

I've been diving into AngularJS and it's been quite fascinating, although I do run into some architectural challenges at times. Let me illustrate with an example.

Imagine we have an application that enables users to create bills. Each bill consists of various lines representing different goods or services, each with properties like title, quantity, cost, and total amount. In JSON format, it might look something like this:

"goods": [
    {
        "title": "Apple",
        "quantity": 3,
        "cost": 5.00,
        "sum": 15.00 // 5.00 × 3
    },
    {...}
]

Additionally, a bill has a total amount calculated by adding up all the item sums. For instance, if we have 3 apples costing $15.00 and 5 bananas costing $10.00, the total bill amount would be $25.00.

The debate arises on the most effective way to calculate amounts within each scope. One method involves having only one scope (for the bill) with predefined methods for sum calculation in every step. Here's a basic pseudocode representation:

$scope.getTotalInItem = function(item) {
    return item.quantity * item.cost
}

$scope.getTotal = function() {
    amount = 0
    for item in $scope.items
    amount += $scope.getTotalInItem(item)
        return amount
}

While this approach simplifies data retrieval from the server without much preparation, it tends to mix all the logic in a single place, which may not be ideal.

Alternatively, another tactic involves creating a separate class for each calculation level, like so:

function Good(title, quantity, cost){
    this.total = function(){
        return this.quantity * this.cost
    }
}

function Bill(goods){
    this.goods = goods
    this.total = function(){
        amount = 0
        for good in this.goods
            amount += good.total()
        return amount
    }
}

This approach, with its delineation of logic levels, seems more organized. However, integrating it effectively with Angular remains a challenge. This method doesn't lend itself easily to fetching JSON data directly from the server and modifying it.

You can find a demonstration of these two approaches here: http://plnkr.co/edit/7t56sIUY83Rnowe8Zb3z?p=preview

In my opinion, it seems necessary to prepare the model after each data fetch and before any data push. This requires convenient helper functions like toJSON() and fromJSON(). What would be considered best practice for implementing such tasks with Angular?

Answer №1

When coding an invoice recently, I encountered a challenge with dirty checking. I had a table of products and used

value="{{ IVACalc().toFixed(2) }}"
, which meant that every time the user made any input changes on the page, the calculation would be triggered again.

With key presses triggering both onkeydown and onkeyup events, this led to double the calculations per key press. To address this issue, it's best to create a separate controller for invoice lines and utilize a service to share data effectively.

This is my approach when working on AngularJS projects:

I start by creating an init.js file where I define my app, dependencies, services, and utilities. External plugins like toastr are encapsulated within a service, though some developers might opt for a directive.

var ViewModule = angular.module('ViewModule',[]);

ViewModule.factory('ViewService', function($rootScope){
  var sharedService = {};
  sharedService.message = '';

  sharedService.init = function(message){
    switch (message){
      case 'productPickView':
        $rootScope.$broadcast('productPickInit');
      break;
      case 'loginView':
        $rootScope.$broadcast('loginViewInit');
      break;
      default :
    }
  };
  //additional code for NotificationCenter

For controllers:

app.controller("productPickCtrl", function($scope, $http, ViewService, 
ConfirmationService, appConfig, NotificationCenter){

I prioritize writing easily readable code to ensure team collaboration and simplify maintenance tasks. Incorporating javadoc or similar documentation practices can further enhance code clarity and developer efficiency.

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

centering an angular material card on the webpage

Currently, I have developed a Registration script that enables users to Sign Up on my website. However, the issue I am facing is that the angular material card, which houses the sign up interface, is not centered. Despite trying various methods such as & ...

When I try to install dependencies with Hardhat, the "Typechain" folder does not appear in the directory

After installing all the dependencies, I noticed that the "typechain" folder was missing in the typescript hardhat. How can I retrieve it? Try running npm init Then, do npm install --save-dev hardhat Next, run npx hardaht You should see an option to se ...

"Patience is key as we await the resolution of a promise within the confines of an emitter

My goal is to wait for the promise to be resolved before continuing when the someevent event is fired. However, even though I use a then in my code snippet below, it seems that the process shuts down before the slowFunctionThatReturnsPromise is resolved, ...

The functionality of Vue.js checkboxes is not compatible with a model that utilizes Laravel SparkForm

I've configured the checkboxes as shown below: <label v-for="service in team.services"> <input type="checkbox" v-model="form.services" :id="service.name" :value="service.id"/> </label> Although they are displayed correctly, the ...

Issue with retrieving relative time using Moment.js - fromNow()

I want to utilize moment.js to display relative time fromNow(), but I am encountering an issue where the values are being rounded and showing higher durations instead of exact completion times. For example, moment().subtract('s',110).fromNow() / ...

What is the process of applying arguments to a class constructor automatically?

In my code, there is an ES6 class called User and a global function named map(): class User { constructor(public name: string) {} } const map = <T, R>(project: (value: T) => R) => {} Instead of the usual way of calling map like this: map ...

Discovering the potential of utilizing an array transmitted by Node/Express on the server-side and integrating it into Google Maps on the client-side

When attempting to set up clustering markers on Google Maps, I encountered a challenge. Client-Side <script> // Code snippet from Google Map docs function initMap() { // Array of locations const locations = [ { lat: -31.56391, lng: 147.15 ...

Ways to validate code that relies on browser APIs

I am currently utilizing Node to run my unit-tests. There is a JavaScript module that I need to test in the browser. My code is considered "isomorphic", meaning it does not use language features that are unavailable in Node, such as exports. However, it ...

It seems that an issue has occurred indicating that something is not defined in the current context

Hello everyone, I'm struggling with a problem that I just can't seem to figure out. I've tried multiple solutions but this error keeps popping up and now I'm completely lost. Can someone please help me resolve this issue? The code in q ...

To properly handle this file type in React, ensure you have the correct babel loader installed

https://i.sstatic.net/iNFs3.pngAn error is triggered when trying to compile with webpack. The message indicates that an appropriate loader may be needed to handle this file type. The libraries I am using are: https://i.sstatic.net/a8fXR.png Below are my ...

c3.js Error: The value of b is not defined

Struggling to create a graph using a JSON object generated in PHP. Despite following the documentation example, I keep encountering a TypeError: b.value is undefined in the JS log. The data seems to be structured correctly. for($i = 0; $i < 10; $i++){ ...

Convert image buffer to string using Mongoose getter?

I have developed a basic node backend application modeled after eBay. I am now working on creating a react frontend app to complement it. Within the app, users can list items for sale and include a photo with their listing. The item information is stored ...

Sending a function parameter when registering for an event

I am currently utilizing the jQuery pubsub for creating custom events: (function($) { var o = $({}); $.subscribe = function() { o.on.apply(o, arguments); }; $.unsubscribe = function() { o.off.apply(o, arguments); }; $.publish = fun ...

Simulated script in a different component

I am looking to simulate the functionality of Amazon AWS S3 getObject The specific code I aim to test is located in helper.js var AWS = require('aws-sdk'); var s3 = new AWS.S3(); exports.get_data_and_callback = function(callback, extra){ s3. ...

Creating a responsive layout that sets the window height to 100% and automatically adjusts sibling divs when the content within parent divs exceeds the defined height

<section> <div class="section-wrap"> <h1>page1</h1> </div> </section> <section> <div class="section-wrap"> <h1>page2</h1> </div> </section> My attempt at impleme ...

The URL for the dynamic import in Workbox is loading incorrectly

For my laravel/vuejs application, I am utilizing workbox and babel dynamic imports. Additionally, I am making use of the laravel-mix and laravel-mix-workbox plugin to compile and generate service worker via generateSW(). The assets load correctly on the r ...

How can we translate HTML entities generated by json_encode into matching XML conventions?

As I embark on the journey of creating a Samsung TV App, I find myself working within a strict system that only allows me to use JS and HTML5. One of the challenges I face is the need to send a JSON request to my web server to retrieve data for the emulato ...

Display the iframe website without it being visible to the user

Is there a way to load a separate website, such as a Wikipedia article, in an iframe on a webpage without freezing up the whole page when it becomes visible after clicking a "show" button? And if not, how can we display a loading gif while the iframe is ...

Trigger a function in JavaScript by clicking on an element and passing its class

I have written the following code: <?php $extCount = 0; foreach($this->externalReferal as $externalReferal) { $extCount++; ?> <div class='fieldtestPct' > <div class='fieldItemLabel'> < ...

The DOM HTMLElement's className property is empty when the element does not have a class name specified

What is the value of the HTMLElement className property when it has no class name set in HTML? Initially, I thought it would be undefined, but I discovered that in Firefox, it is actually an empty string. This raises the question - can this behavior be r ...