DropDown Select In Angular
Table of Contents
1 Summary
I am using angularjs as mobile web framework in my project, and when I use dropdown select control I find interesting things.
Enviroment : angularjs 1.4.6, odoo 8.0(server side), pycharm, chrome, ubuntu 14.04
2 Single dropdown select
Firstly, if I want to make a single dropdown select, I using as follows:
<select name="select1" ng-model="model1" ng-options="option1.id as option1.name for option1 in options1"> <option value="">---Pick One---</option> </select>
In this case,options1 is a array containing objects, such as
[{id:1,name:'apple'},{id:2,name:'pear'}].
When I choose one
option1.name, the model1 is binding to option1.id. Also, the options1
can be a object, or option1.id as option1.name
can write in other ways
depend on needs, you can learn more refer to
Angularjs doc.
Back to example, When I want to generate the options, data from server
is like this: [{id:1,name:'apple'},{id:2,name:'pear'}].
, of course
remember dump to json. And when I console.info()
in the browser, It
adds $$hashkey
to each object, the data becomes this:
[{id:1,name:'apple',$$hashKey: "object:123"},{id:2,name:'pear',$$hashKey: "object:124"}]
,But
$$hashkey
doesn't affect others. If I want the options selected when
the page loaded, I also afferent the id
from server side, so I can set
the model1 to id to make it selected.
When option is selected, just post the data of model1 to server,so the server knows which one is selected.
3 Multle-select dropdown select
Secondly, I want to multle-select dropdown select. that's simple, just
add multiple
"multiple"= to HTML conrol like following:
<select name="select2" ng-model="model2" ng-options="option2.id as option2.name for option2 in options2" multiple="multiple"> <option value="">---Pick Many---</option> </select>
From the browser side,simply,the Get data(from server) is like this
format:
[{id:1,name:'apple'},{id:2,name:'pear'},{id:3,name:'orange'}]
,(also,angular
will add $$hashkey
in each object) and if you want pre-selected, also
set model2 to id list ,the format like this [1,3]
. The Post data is
like {ids:"[1,3]"}
, rember to tranfer to json using:
JSON.stringify()
before post to server.
4 Cascading dropdown seletion
Finnally, I want make a cascading dropdown seletion, for example, I want to pick country, state, area in turn, here I make up two ways.
4.1 First solution:
<!-- HTML --> <select ng-model="selectedCountry" ng-change="selectedUnit=''" ng-options="country as country.name for country in countries" > <option value="">---Pick Country---</option> </select> <select ng-model="selectedState" ng-change="selectedArea=''" ng-options="state as state.name for state in selectedCountry.state"> <option value="">---Pick State---</option> </select> <select ng-model="selectedArea" ng-options="area as area.name for area in selectedState.area"> <option value="">---Pick Area---</option> </select>
#Get data from server like this [ {id:1,name:"country1",state:[ {id:101,name:"state1",area:[{id:10101,name:"area1"},{id:10102,name:"area2"},{id:10103,name:"area3"}]}, {id:102,name:"state2",area:[{id:10201,name:"area4"},{id:10202,name:"area5"},{id:10203,name:"area6"}]}, {id:103,name:"state3",area:[{id:10301,name:"area7"},{id:10302,name:"area8"},{id:10303,name:"area9"}]} ] }, {id:2,name:"country2",state:[ {id:201,name:"state4",area:[{id:20101,name:"area11"},{id:20102,name:"area12"},{id:20103,name:"area13"}]}, {id:202,name:"state5",area:[{id:20201,name:"area14"},{id:20202,name:"area15"},{id:20203,name:"area16"}]}, {id:203,name:"state6",area:[{id:20301,name:"area17"},{id:20302,name:"area18"},{id:20303,name:"area19"}]} ] }, {id:3,name:"country3",state:[ {id:301,name:"state7",area:[{id:30101,name:"area31"},{id:30102,name:"area32"},{id:30103,name:"area33"}]}, {id:302,name:"state8",area:[{id:30201,name:"area34"},{id:30202,name:"area35"},{id:30203,name:"area36"}]}, {id:303,name:"state9",area:[{id:30301,name:"area37"},{id:30302,name:"area38"},{id:30303,name:"area39"}]} ] } ] #Also,when angularjs get this data(of json format) from server,it tanfer it, and add $$haskkey to each object,including object in object.
So,if i want to pre-select options, I need also get the country id,state id,and area id from the server, and in angularjs controller, use the given id to get object from transfered data(in order to get \[haskkey also, I didn't do this on server because in server data don't contain `\]hashkey`),so the three object may look like this:
//selectedCountry {$$hashkey:"objectxx",id:2,name:"country2",state:[ {$$hashkey:"objectxx",id:201,name:"state4",area:[{$$hashkey:"objectxx",id:20101,name:"area11"},{$$hashkey:"objectxx",id:20102,name:"area12"},{$$hashkey:"objectxx",id:20103,name:"area13"}]}, {$$hashkey:"objectxx",id:202,name:"state5",area:[{$$hashkey:"objectxx",id:20201,name:"area14"},{$$hashkey:"objectxx",id:20202,name:"area15"},{$$hashkey:"objectxx",id:20203,name:"area16"}]}, {$$hashkey:"objectxx",id:203,name:"state6",area:[{$$hashkey:"objectxx",id:20301,name:"area17"},{$$hashkey:"objectxx",id:20302,name:"area18"},{$$hashkey:"objectxx",id:20303,name:"area19"}]} ] } //selectedState {$$hashkey:"objectxx",id:202,name:"state5",area:[{$$hashkey:"objectxx",id:20201,name:"area14"},{$$hashkey:"objectxx",id:20202,name:"area15"},{$$hashkey:"objectxx",id:20203,name:"area16"}]} //selectedArea {$$hashkey:"objectxx",id:20202,name:"area15"}
In this case,it can work. If you set selectedCountry or selectedState or
selectedArea without $$hashkey
, It don't show pre-selected data I
want.
The problem of this method is:when the data gets more, each time I load this page, the server will caculate to generate this format data(or you can store it depend on your need), and the client side will caculate also to get the hash key.It is slow and waste performance because in most case, the data is the same(also depend on your situation).
What is $$hashkey
? I find this answer from
stackoverflow:
>Angular adds this to keep track of your changes, so it knows when it
needs to update the DOM.If you use angular.toJson(obj) instead of
JSON.stringify(obj) then Angular will strip out these internal-use
values for you.
Also, if you change your repeat expression to use the track by {uniqueProperty} suffix, Angular won't have to add $$hashKey at all. For example
<ul> <li ng-repeat="link in navLinks track by link.href"> <a ng-href="link.href">{{link.title}}</a> </li> </ul>
Just always remember you need the "link." part of the expression - I always tend to forget that. Just track by href will surely not work.
Another helpful: >In my use case (feeding the resulting object to X2JS) the recommended approach
data = angular.toJson(source); help to remove the $$hashKey properties, but the result could then no longer be processed by X2JS.
data = angular.copy(source); removed the $$hashKey properties as well, but the result remained usable as a parameter for X2JS.
4.1.1 Problem left
Then I wonder if I remove $$hashkey
all, would it work and be simpler
for data processing?
4.2 Second Solution
However, I choose the second solution:
<!--HTML--> <select ng-model="vm.newCountryId" ng-change="vm.getState()" ng-options="country.id as country.name for country in vm.countrys" > <option value="">--select country--</option> </select> <select ng-model="vm.newStateId" ng-change="vm.getArea()" ng-options="state.id as state.name for state in vm.states" > <option value="">--select state--</option> </select> <select ng-model="vm.newAreaId" ng-options="area.id as area.name for area in vm.areas" > <option value="">--select area--</option> </select>
And function (also getCountry()),getState(),vm.getArea() I write in angular controller to get data list from server. So each time when i select a value, it trigger a funtion to get data from server.Also in the funtion I use the Id to point what data I want get from server.The code is some like this:
// In controller vm.getArea = function(){ //Needs attention here if(vm.newStateId==null){ vm.newAreaId=null; return; } dataService.getArea(vm.newStateId) .then(function (data) { vm.areas = data; $timeout(function () { }, 1000); }, function (error) { toaster.pop('error', "errormsg", "errormsg..."); }); };
//process pre-select data from server. Just get 3 id from the server, and the get one by one from server if(data['country_id']){ vm.newCountryId = data['country_id']; vm.getState(); if(data['state_id']){ vm.newStateId = data['state_id']; vm.getArea(); if(data['area_id']){ vm.newAreaId = data['area_id']; } } }
In this method, Post data is just 3 ids. This is simple, and speed fast comparing the former solution.And the data and logic is also simple and clear.
This is my first blog, maybe it looks verbose and not clearly, I am sorry for that, I will keep trying to make it better.:)