1

I have a <select> with an ng-model. I want the values of my <option>s to be JSON objects.

When a user selects an option, I want to display individual properties from the selected object.

I have the following plunker showing what I am trying to achieve.

<div ng-controller="myCtrl as vm">

    <div>
        Person: 
        <select ng-model="vm.person">
            <option value='{"name": "Matt", "age": "21"}'>Matt</option>
            <option value='{"name": "John", "age": "22"}'>John</option>
        </select>
    </div>


    <br>
    Person: <input type="text" ng-model="vm.person">
    Name: <input type="text" ng-model="vm.person.name">
    Age: <input type="text" ng-model="vm.person.age">

</div>

The issue is that vm.person is a string, not an object, so I cannot access properties of it.

I have tried fromJson but that throws an error because it is non assignable (which is sensible).

<input type="text" ng-model="angular.fromJson(vm.person.name)">

I could watch for a change on vm.person, then do an angular.fromJson there, but that doesn't feel right. It feels like there is a better way.

I essentially want to parse the string before it gets to the model, so that by the time it get's to the model, it is a javascript object. This will allow me to access properties of that object.

What is the correct way to handle this in angular?

If there is no "angular" way, what is the common way to handle this in Javascript?


EDIT

A forked plunker to show the effects of adding a $scope.$watch.

function myCtrl($scope){
    var vm = this;

    $scope.$watch('vm.person', function(){
        vm.person = angular.fromJson(vm.person);
    })
}

This allows the Name and Age inputs to be populated correctly, but it breaks the select (it isn't populated by the selected value anymore because the model is changed).

15
  • 1
    why not retrieving the vm as json format? not a string? Commented Mar 9, 2016 at 10:00
  • @EuphoriaGrogi I'm sorry, I don't understand what you mean. Retrieving the vm from where? Commented Mar 9, 2016 at 10:05
  • can you show me your controller and service if you have? Commented Mar 9, 2016 at 10:06
  • There is a link to a plunker in the question. My controller has nothing in it, for the sake of simplicity, let's assume the values of my options are hard coded JSON strings. I have no service, this is just a simple example. Commented Mar 9, 2016 at 10:11
  • read first angular two-way binding, the properties you specified in ng-model directives must be declared in the scope of your controller, unless you leave this controller empty Commented Mar 9, 2016 at 10:13

2 Answers 2

6

How about using ng-options, You can pass the object from the controller and then have the select on the basis of that.

HTML:

 <div ng-controller="myCtrl as vm">
   <select ng-options="selected.name for selected in vm.person" ng-model="vm.customPerson">
      <option value="" disabled>Person</option>
   </select>
   <br>
   <br>
   Person: <input type="text" ng-model="vm.customPerson">
   <br>
   Name: <input type="text" ng-model="vm.customPerson.name">
   <br>
   Age: <input type="text" ng-model="vm.customPerson.age">
</div>

JS:

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

app.controller('myCtrl',
function($scope){
  this.person=[
      {name: 'Matt',    age: '12'},
      {name: 'John',     age: '23'},
    ];
});

I hope the following Plunker satisfies what you are intending to get.

PLUNKER:http://plnkr.co/edit/rU5vW5KuvJNJOr7tSOPq?p=preview

Sign up to request clarification or add additional context in comments.

2 Comments

Yes, this is exactly what I was trying to do. This is the cleanest solution in my opinion.
I am glad i could be of some service to you :)
2

Not sure if you want the results in this way only. You can achieve the results you want after changing the code to below,

Controller code:

script.js

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

app.controller('myCtrl', myCtrl);

function myCtrl() {

var self = this;
self.persons = [];
self.persons[0] = {
    "name": "Matt",
    "age": "21"
};
self.persons[1] = {
    "name": "John",
    "age": "22"
};
self.personSelected = personSelected;

function personSelected(personName) {
    var i = 0;
    console.log("Person selected called..")
    self.selectedPerson = {};
    for (i = 0; i < self.persons.length; i++) {
        if (self.persons[i].name == personName) {
            self.selectedPerson = self.persons[i];
            break;
        }
    }
}
}

HTML code:

<body ng-app="app">
<div ng-controller="myCtrl as vm">

  <div>
     Person: <select ng-model="vm.person" ng-change="vm.personSelected(vm.person)">
       <option>Matt</option>
       <option>John</option>
     </select>
  </div>


  <br>
  Person: <input type="text" ng-model="vm.selectedPerson">
  <br>
  Name: <input type="text" ng-model="vm.selectedPerson.name">
  <br>
  Age: <input type="text" ng-model="vm.selectedPerson.age">

  </div>
</body>

4 Comments

Thanks for the answer. This is better than nothing, but I was hoping for more of a way to do this without manually having to add things to the vm.selectedPersons or equivalent. Just more of a "set the value on this model and then have the DOM update itself" (as you would if the value was simply a string, not an object)
May be this can help.... You could have a getter setter function, then on ng-change set the vm.selectedPerson variable there and bind it
This answer doesn't work for my situation, and I personally don't like the idea of calling a function each time it changes. However, this is still useful for other people so still a +1.
@NehaSaggam, you wrote good. However, its like killing a fly with a cannon :) +1 for your hardwork. GOD, i reached my voting limit :( sorry about that. will drop by later.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.