Utilizing Angular's binding feature with objects

Clarifying the question for better understanding.

Plunkr
Preview:

<input type="text" ng-model="form['data']['sampleData']">
    <input type="text" ng-model="form[bindingPrefix][bindingSuffix]">
    <input type="text" ng-model="form[bindingValue]">

Controller:

    $scope.form = {
    data: {
      sampleData: '123'
    }
  };

  $scope.bindingValue = 'data.sampleData';
  $scope.bindingPrefix = 'data';
  $scope.bindingSuffix = 'sampleData';

Intended outcome: I anticipate that form[bindingValue] will produce the same result as

form[bindingPrefix][bindingSuffix]</code without manually splitting <code>bindingValue
into bindingPrefix and
bindingSuffix</code since bindingValue can be a dynamic value like <code>data.sampleData.childData
,
data.sampleData.childData.childChildData
in an array for ng-repeat the model.

Note: bindingValue is a value passed from Server side over which I have no control.

========================================================================== This Plunkr might offer a solution. It is preferable not to modify the view if possible.Click here

Answer №1

Although the pathway may vary in length, we can simplify the issue by utilizing a single variable path. This approach remains effective as long as the structure of the data object remains intact (or if altered, be sure to rerun the preparatory code).

Here is the data:

$scope.form = {
    data: {
      sampleData: '123'//The depth of this could be unknown
    }
};

However, the only essential variable required to maintain the connection between sampleData and its container is the final one - "sampleData". The other property names can be discarded once we acquire a reference to the data object and the "sampleData" property name.

Within the controller:

//Retrieve the server path, split it to form an array of property names
var path = 'data.sampleData'.split('.');
//Modifications will commence shortly
var prevValue = $scope.form;
var nextValue;

for(var i = 0; i < path.length - 1; i++){ //(Note that we are not looping all the way through (-1)!)
    //Access each property step by step
    nextValue = prevValue[path[i]];
    if(nextValue == undefined){
        //This indicates an error where the expected property was not present in the data.
        //Handling this situation is up to you. Executing the following code will insert the missing properties to maintain functionality.
        nextValue = prevValue[path[i]] = {};
    }
    //Initially, prevValue refers to $scope.form, then form.data
    prevValue = nextValue;
 }
 //$scope.bindingContainer denotes a pointer to $scope.form.data object
 $scope.bindingContainer = prevValue;
 //$scope.bindingValue represents the final property name, "sampleData"
 $scope.bindingValue = path[path.length-1];

In the template:

<input type="text" ng-model="bindingContainer[bindingValue]">

Everything should function smoothly (providing no alterations like $scope.form.data = somethingElse occur).

We are bending the rules slightly since now the template does not directly mention the original $scope.form object. Yet, this should not pose an issue because it holds a reference to the data object and its "sampleData" property. As long as $scope.form still points to the same data object, we have everything necessary.

Answer №2

A new custom directive named my-dynamic-model has been developed to be used with <input> elements in your Angular application. This directive facilitates referencing a scope variable, $parsed, which points to the correct array within $scope.bindingValue.

To see this directive in action, check out the live demonstration on Plunker.

With this custom directive, you can now specify nested hierarchies within $scope.bindingValue and ensure that any updates will be reflected accurately in the respective $scope variable. Just remember to provide a complete path in the $scope object hierarchy.

IMPLEMENTATION:

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

app.controller('MyController', function($scope) {
  $scope.form = {
    data: { 
      sampleData: '1234',
      sampleData1: {
        sampleData2: '2345'
      }
    }
  };

  $scope.bindingValue = ['form.data.sampleData', 'form.data.sampleData1.sampleData2'];
});


app.directive('myDynamicModel', function( $parse, $log ) {
    return function( scope, el, attrs ) {
        var model = $parse( attrs.myDynamicModel );
        var finalModel = $parse(model(scope));

        finalModel.assign(scope, finalModel(scope));
        scope.$apply();

        el.bind('keyup', function() {
            finalModel.assign(scope, el.val());
            if (!scope.$$phase) scope.$apply();
        })
    }
});

USAGE IN HTML:

<div ng-controller="MyController">
    <input type="text" ng-model="form.data.sampleData" my-dynamic-model="bindingValue[0]" placeholder="Update me">
    <input type="text" ng-model="form.data.sampleData1.sampleData2" my-dynamic-model="bindingValue[1]" placeholder="Update me too">

  <div>{{ form.data.sampleData }}</div>
  <div>{{ form.data.sampleData1.sampleData2 }}</div>
</div>

Answer №3

Perhaps you are currently working with Angular and exploring different syntax options. If so, check out this insightful article on the controller as syntax.

function ExampleCtrl($scope) {
    $scope.bindingValue = data.sampleData;
    $scope.bindingPrefix = 'data';
    $scope.bindingSuffix = 'sampleData';
}
// Controller or Controller as syntax is just a shorthand name for the controller.
<body ng-app="ExampleApp">
  <div class="example" ng-controller="ExampleCtrl">
    <input type="text" ng-model="bindingValue">
  </div>
</body>

You can try a different syntax variation like this:

function ExampleCtrl() {
  var ctrl = this;

  ctrl.bindingValue = data.sampleData;
  ctrl.bindingPrefix = 'data';
  ctrl.bindingSuffix = 'sampleData';
}
<body ng-app="ExampleApp">
  <div class="example" ng-controller="ExampleCtrl as ctrl">
    <input type="text" ng-model="ctrl.bindingValue">
  </div>
</body>

Answer №4

To begin, construct a scope object within your controller:

$scope.data = {
    sampleData: {
        childSampleData: null
    },
    additionalItem: null,
    moreInfo: {
        Child1: null,
        Child2: null
    }
}

Next, ensure that your HTML references the scope object correctly:

<input type="text" ng-model="data.sampleData.childSampleData">
<input type="text" ng-model="data.additionalItem">
<input type="text" ng-model="data.moreInfo.Child1">
<input type="text" ng-model="data.moreInfo.Child2">

It is important to note that you cannot access an ngModel in the manner shown in your code snippet. Therefore, using

ng-model="form[bindingPrefix][bindingSuffix]"
is incorrect as the form object cannot be accessed in this context. Instead, make use of dot notation to access child objects as demonstrated in the HTML.

If there are uncertainties regarding which ngModel needs updating, consider implementing a function like the following:

<input type="text" ng-model="item1" ng-change="updateModel()">

$scope.updateModel = function() {
    $scope.data[bindingPrefix][bindingSuffix] = $scope.item1;
}

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

Dealing with performance issues in VueJS and Vuetify's data-table component, especially when trying to implement

In my VueJS and Vuetify project, I encountered an issue. I am trying to create a table with expandable rows for displaying orders and their associated products. The table needs to show at least 100 rows of orders on one page. To achieve this, I utilized th ...

Graphql query using $http.post is unsuccessful

I successfully made a request for the code below, but I am encountering an issue where I am not receiving any data back. The "preview" tab of the request in Chrome simply displays "Error Not Found". Interestingly, when I try the same query in GraphiQL, i ...

Ways to adjust the quantity of a product in PHP MySQL or JavaScript, including methods for increasing, decreasing, and inserting a quantity value with a checkbox option

Is it possible to adjust or remove the quantity of a product using PHP MySQL or Javascript? Can you also include a checkbox for setting a quantity value along with a product? <form action="addtocart.php" method="post"> <table width="100%" c ...

Passport.js is throwing an error due to an unrecognized authentication

I need to implement two separate instances of Passport.js in my application - one for users and one for admins, both using JWT authentication. According to the official documentation, the way to differentiate between them is by giving them unique names. W ...

Exploring the concept of importing components from different pages in NextJS

I'm currently navigating the Next.JS framework and struggling to grasp the concept of importing data from a component page. Let's say I've created a page named example.js in my components folder, where I'm fetching data from an API to d ...

Exploring the depths of a multidimensional dictionary within AngularJS

I am currently working on a project using AngularJS. The data I have is in the form of JSON: { "leagues":{ "aLeague":{ "country":"aCountry", "matchs":{ "aUniqueID1":{ "date":"2014-09-07 13:00:00", "guest_play ...

Steps to have the initial link redirect to a designated webpage

I am working with tables that have links defined in the HTML. I want to modify the behavior so that the first link opens a different URL, for example: john.com. Is it possible to achieve this? Specifically, I want the link associated with the first name ( ...

Is the issue of res.locals not being properly propagated to all requests in Express middleware persisting?

Currently, I am building a web app using express, node, and handlebars with passport as the authentication library. In an attempt to customize the navigation bar based on the user's state, I am trying to set a variable in res.locals. However, I am enc ...

One of the parameters is converging faster than the other with Gradient Descent

My introduction to univariate linear regression using gradient descent was a hands-on experience in JavaScript. const LEARNING_RATE = 0.000001; let m = 0; let b = 0; const hypothesis = x => m * x + b; const learn = (alpha) => { if (x.length < ...

Error 400 when uploading files in Angular2 using multipart/form-data

When attempting to upload a file along with some meta information using multipart/form-data, the format should look like this: Header ----boundary Meta ----boundary File ----boundary Despite following this format, I consistently receive a 400 Error from ...

utilizing the data provided by a user in the "prompt" window within my HTML code

Looking to utilize user input from the prompt window. This is my custom JavaScript form: var answer; function load() { answer=prompt("what is your name?", "Write your name here"); return answer; } function hideNsee() { var HNS = docume ...

JavaScript: Share module contents internally through exporting

When working with Java, there are 4 different visibility levels to consider. In addition to the commonly known public and private levels, there is also the protected level and what is referred to as the "default" or "package-local" level. Modifier Clas ...

A guide on implementing nested child routes in AngularJS 2

I have successfully completed routing for two children, but now I want to display nested routes for those children. For example: home child1 child2 | grand child | grand child(1) ...

The perplexing configuration of a webpack/ES6 project

I am currently in the process of setting up my very first ES6 and webpack "application" where I aim to utilize classes and modules. However, each time I attempt to transpile the application using the webpack command, I encounter the following error: $ web ...

Is it possible to transfer the JSON data received from a POST request to the client?

I have a Node.js server running with Express that listens to incoming requests. I want to update an HTML file when I receive a GET request in my server, but the data sent to my server is from an API triggered by an external event asynchronously. I'm s ...

Refreshing a PNG file without the need to refresh the entire page

Developed a captcha using imagestring imagestring($image, 5, 5, 30, $text, $text_color); imagepng($image,"captcha_image.png"); imagepng($image,"captcha_image.png"); The code snippet above shows part of the implementation. <img ...

Tips on transferring form data from client to server in meteor

In the process of developing my e-commerce application, I am facing a challenge with passing data from the client to the server. Specifically, I need to send information like the total cost of items in the cart and the list of items selected by users so ...

Using Vuetify 3 to conditionally render v-icon inside a v-data-table

I am struggling to display a v-icon conditionally in a v-data-table within Vuetify 3, based on a value of either 1 or 0. In Vuetify 2, there were multiple easy ways to achieve this, but it's not rendering in the latest version. I want to show v-icons ...

A straightforward Node.js function utilizing the `this` keyword

When running the code below in a Chrome window function test(){ console.log("function is " + this.test); } test(); The function test is added to the window object and displays as function is function test(){ console.log("function is " + this.tes ...

Learn how to utilize Vue 3 to access properties that have been passed down from a parent component, even if they

Hey there, hope everything is going well. I'm familiar with react.js, but when I gave vue a try, things felt a bit different. In react, it's easy to access props passed from the parent in the child component without much hassle. However, in vue, ...