What is the best way to assign an ngModel dynamically using a dot-separated path?

I have noticed a few questions that are similar to this one, but my question has a slight variation.

In my controller, I have an object that resembles the following:

$scope.data = {
  foo: {bar: 1,
        bas: 2},
  biz: 3,
  blat: 4
};

My goal is to create an input field where the ng-model can be dynamically assigned to any of those values.

<label>Define Model</label>
<input type="text" ng-model="input.model" />

<label>Data for {{input.model}}:</label>
<input type="text" ng-model="{{input.model}}">

Essentially, I would like to be able to set the "Define Model" input to something like data.foo.bas and have the corresponding "Data for data.foo.bas" input display a value of 2.

I am aware that I can achieve a similar result with the following code:

<label>Define Model</label>
<input type="text" ng-model="input.model" />

<label>Data for {{input.model}}:</label>
<input type="text" ng-model="data[input.model]">

However, this method only allows me to access the biz and blat attributes. Does anyone have any suggestions on how this can be accomplished? Thank you.

Answer №1

If you want to extract values from $parse

$scope.$watch('input.model', function(newVal) {
    $scope.definedModel = $parse(newVal)($scope.data);
});

In this case, $parse will look for a match in $scope.data and assign it to definedModel

Check out this plunker

Answer №2

If you want to achieve this, you will need to make a small adjustment to the structure of your data array. Each model should have its own object instead of just being a primitive, all with a common structure:

var data = {
  foo: {
    bar: {
      value: 1
    },
    bas: {
      value: 2
    }
  },
  biz: {
    value: 3
  },
  blat: {
    value: 4
  }
};

This adjustment allows you to pass the objects around so that ngModel can still refer to (and modify) the original object.

You will also need a function to convert a "path" like "foo.bas" to retrieve the correct object, you can refer to this answer for guidance:

var getProperty = function(obj, prop) {
  var parts = prop.split('.'),
      last = parts.pop(),
      l = parts.length,
      i = 1,
      current = parts[0];

  if (l === 0) return obj[prop];

  while((obj = obj[current]) && i < l) {
      current = parts[i];
      i++;
  }

  if(obj) {
      return obj[last];
  }
}

Additionally, you must monitor the input.model variable to ensure that the scope's model variable is assigned to the correct object:

$scope.$watch('input.model', function(name) {
  $scope.model = getProperty(data, name);
});

Finally, all of this is controlled by inputs that define "input.model" and "model" on the scope:

<input placeholder="Model name" ng-model="input.model" />
<input placeholder="Model value" ng-model="model.value" />

You can see this in action in this Plunker.

Edit: Alternatively, according to the answer from @Reza, you can use $parse instead of the getProperty function mentioned above. With this method, the watcher can be simplified to:

$scope.$watch('input.model', function(name) {
  $scope.model = $parse(name)(data);
});

You can view this alternative approach in action in this Plunker. It is indeed a neater solution with less code.

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

Initializing an Express app with JSON file loading

My movie-finding application relies on backend API calls to function. As part of the initialization process, I need to load two JSON files: one containing a list of languages for searching (lang.json) and another stored in the config variable that provides ...

Top method for extracting mesh vertices in three.js

Being new to Three.js, I may not be approaching this in the most optimal way, I start by creating geometry like this: const geometry = new THREE.PlaneBufferGeometry(10,0); Next, I apply a rotation: geometry.applyMatrix( new THREE.Matrix4().makeRotation ...

What is the best way to darken the background when an alert is displayed and disable the dimming effect when the alert is closed?

Here's the JavaScript snippet I'm using: reset.addEventListener("click", function(){ document.querySelector("#body").classList.add("darkenPage"); myReset(); alert("Reset Successful!!"); document.querySelector("#body").classList.re ...

Is there a way to upload files in AngularJS without using AJAX or jQuery?

Currently, I am looking to create a gallery that allows for the uploading of multiple images. While I have come across some options that utilize ajax to immediately send the files, I prefer a solution that involves form submission. In addition, I would li ...

tips for successfully transferring date and time data between json and nosql databases like firestore

Input: Created_At:Monday, 29 April 2019 15:07:59 GMT+05:30 Updated_At:Monday, 29 April 2019 15:07:59 GMT+05:30 I attempted to export data in JSON format from Firestore using the npm package firestore-export-import. However, the output I received was: ...

Error occurs when page rendering is stuck in a recursive loop: Excessive re-renders detected

My webpage contains several form components as listed below. While everything on the front end seems to be working fine, I noticed that the Fetchmovies function is being called repeatedly and an error is thrown in the console: caught Error: Too many re-ren ...

Automatically activate the Focus Filterfield in the ng-multiselect-dropdown upon clicking

I've integrated the ng-multiselect-dropdown package into my Angular project using this link: https://www.npmjs.com/package/ng-multiselect-dropdown. Everything is functioning as expected, but I'm looking to automatically focus on the filter input ...

Transform CSS into React.js styling techniques

My current setup involves using Elementor as a REST Api, which is providing me with a collection of strings in React that are formatted like this: selector a { width: 189px; line-height: 29px; } Is there a tool or library available that can conver ...

AngularJS allows for the creation of 2D arrays using the $Index

Currently, I am working on a project using AngularJS that involves creating a spreadsheet from a 2D array generated by the ng-repeat function. As part of this project, I am developing a function to update the initial values of the array when users input ne ...

How is it possible for the output to be a string array when the variable was declared as a number in TypeScript?

Snippet: function sampleFunction(sample:string|number|string[]) { if(typeof sample == "string") { console.log("Sample is String " + sample); } else if(typeof sample == "number") { console.log("Sample is Number " + sampl ...

The issue with calling Ajax on button click inside a div container is that the jQuery dialog box is

Here is the code for my custom dialog box: $("#manageGroupShow").dialog({resizable: false, draggable: false, position:['center',150], title: "Manage Group", width:"50%", modal: true, show: { effect:"drop", duration:1000, direction:"up" }, hide: ...

Is jQuery Autocomplete functioning properly on outdated browsers, but not on newer ones?

Here is the JSON data I have for my auto complete feature { "list" : [ { "genericIndicatorId" : 100, "isActive" : false, "maxValue" : null, "minValue" : null, "modificationDate" : 1283904000000, "monotone" : 1, "name":"Abbau", ...

I am interested in displaying the PDF ajax response within a unique modal window

With the use of ajax, I am able to retrieve PDF base64 data as a response. In this particular scenario, instead of displaying the PDF in a new window, is it possible to display it within a modal popup? Any suggestions on how this can be achieved? $.ajax ...

Extracting dynamic content from a webpage using Selenium with Javascript rendering capabilities

Seeking a way to extract data that populates the SVG elements on a specific page: The page seems to be driven by JavaScript, making traditional BeautifulSoup methods in Python ineffective. After inspecting the network for XHR requests, it doesn't see ...

The function Router.push("/") is not functioning as expected when called within the pages/index.js file

Currently, I'm utilizing the Next JS next-auth/react library and aiming to direct authenticated users straight to the dashboard. Here's a snippet from my index.js file: import { useRouter } from "next/router"; import Link from "nex ...

Conceal particular table cells through jQuery

I am a beginner in the world of jQuery. My goal is to hide certain cells in a row when clicked, and have them displayed again when clicked once more. I've searched high and low for a solution, but all I find is how to hide entire rows. Here's an ...

Vue 2 checkbox form array data

Creating a checkbox list with a dynamic id and name: Data: yards[{id:1,name:'test'}] etc HTML: <ul class="checkbox-list"> <template v-for="(yard, index) in yards"> <li> ...

The initial render in a Kanban board seems to be causing issues with the functionality of react-beautiful-dnd

I recently integrated a Kanban board into my Next.js and TypeScript project. While everything seemed to be working fine, I encountered a minor glitch during the initial rendering. Interestingly, when I refreshed the page, the drag and drop functionality st ...

Updating data for a heatmap in Angular-Leaflet

My goal is to display a dynamic heatmap using the Angular-Leaflet directive. I have written the following code: getData().then(function (data) { $scope.heat.index = 0; $scope.heat.data = data; $scope.layers.overlays.heat = { name: "Hea ...

Waiting for Angular's For loop to complete

Recently, I encountered a situation where I needed to format the parameters and submit them to an API using some code. The code involved iterating through performance criteria, performance indicators, and target details to create new objects and push them ...