Deep linking with <select>, angular js - angularjs

I want to enable deep linking with the select element
<select ng-model="query">
<option ng-repeat="product in products">{{product.code}}</option>
</select>
So when I choose something, I want the url to change to app/productcode
Any ideas?

You should change your select to:
<select ng-model="query" ng-options="product.code for product in products"></select>
In your controller, you'll use the $location service to change to the route you want via a watch. Something along the lines of:
$scope.$watch('query', function() {
$location.path('/some/route/' + query);
});

Related

ng-repeat in controller to change DOM with js

I have JSON which stores a list of options. I want to manipulate the DOM with jQuery in controller. For example, I have a <div id="div"></div> in html and I want to do
$scope.options = "options come from JSON";
$('#div').append("<select ng-model='model'><option ng-repeat='opt in options'>{{opt.value}}</option></select>")
in controller. When I open the html page <select></select> tag is coming but options are empty. My question is that how can I loop options with ng-repeat in controller and send to html page? Thank you.
You should prefer using Angular ng-options:
<select ng-model="model" ng-options="opt.value for opt in options"></select>
As a side note (despite the fact that this code can work), you should avoid doing DOM manipulations on an AngularJS app. It is not JQuery, and it is not the Angular way to do this.
Please don't do DOM manipulation in such a simple example - in general, you should save it for directives. Just write this in your HTML straight up:
<div id="div">
<select ng-model='model'>
<option ng-repeat='opt in options'>{{opt.value}}</option>
</select>
</div>
Could do something like this
//View
<select ng-if="options">
<option ng-repeat="opt in options">{{opt.value}}</option>
</select>
//Controller
$scope.options = <The JSON object>;

ng-selected not working in select field

I am trying to set the default value of a select field to a set option but its not working and I can't seem to figure out what am I doing wrong?
In my controller I have:
$scope.interp_id = "2"; // set the default id
$http.get("web/controllers/get.php")
.then(function (response) {
$scope.interpreters = response.data.records;
});
get.php is a php file that returns json (this is working properly).
My select looks like:
<select ng-model="interpreters_id">
<option ng-repeat="x in interpreters" value="{{x.id}}" ng-selected="{{x.id == interp_id}}">{{x.first_name}} {{x.middle_name}} {{x.last_name}}</option>
</select>
When I go to view it in my browser it looks like:
but when I inspect the element it shows that option ng-selected is True.
what am I doing wrong?
ngOptions is the recommended way to use select elements in Angular.
Also, if you look at the ngSelected documentation there is a yellow box that states that it does not work properly with the select and ngModel properties which is, in a way, what you are trying to do.
ngRepeat will gladly repeat your option elements however it is not the correct way to work with a select element.
I have prepared a fiddle for you to try it out.
<div ng-app="ngOptionsApp">
<div ng-controller="ExampleController">
<select ng-model="selectedInterpreter" ng-options="interpreter as interpreter.name for interpreter in interpreters track by interpreter.id">
<option value="">Select an Interpreter</option>
</select>
{{selectedInterpreter}}
</div>
</div>
angular.module('ngOptionsApp', []).controller('ExampleController', ['$scope', function($scope) {
$scope.interpreters=[{id: 1, name:'Gill Bates'}, {id: 2, name:'Cohn Jarmack'}, {id: 3, name:'Melon Musk'}];
$scope.selectedInterpreter = $scope.interpreters[0];
}]);
Hope it helps ;)
You should not use the curly braces in ng-selected directive. May you try this?
<option ng-repeat="x in interpreters" value="{{x.id}}" ng-selected="x.id == interp_id">{{x.first_name}} {{x.middle_name}} {{x.last_name}}</option>
http://jsfiddle.net/endrcn/44j19ngp/

AngularJS - Populating HTML Drop-Down with JSON from REST API (without $scope)

A lot of solutions on Stack Overflow in relation to populating drop down menus include $scope.
My second drop-down depends on the value of my first drop-down therefore I use ng-changeon the first HTML select to parameter pass the model ID into the 2nd drop-down's function.
1st Drop-Down HTML and Angular JS:
<select data-ng-controller="addAssetController as addAssetCtrl" id="functionalOrg" data-ng-model="addAssetFormCtrl.functionalOrg.id" ng-change="addAssetCtrl.getLocations(addAssetFormCtrl.functionalOrg.id)">
<option data-ng-repeat="functionalOrg in addAssetCtrl.functionalOrgs | orderBy:'id' track by $index" value="{{functionalOrg.id}}">
{{functionalOrg.id}} - {{functionalOrg.account}}
</option>
</select>
Hence ng-change:
ng-change="addAssetCtrl.getLocations(addAssetFormCtrl.functionalOrg.id)"
-
var vm = this;
functionalOrganisationRepository.getFunctionalOrganisation().then(function (results) {
vm.functionalOrgs = results;
}, function (error) {
vm.error = true;
vm.errorMessage = error;
});
The 2nd Drop-Down HTML and Angular:
<select data-ng-controller="addAssetController as addAssetCtrl" id="location" data-ng-model="addAssetFormCtrl.location.id">
<option data-ng-repeat="location in addAssetCtrl.locations | orderBy:'id' track by $index" value="{{location.id}}">
{{location.id}} - {{location.address6}}
</option>
</select>
-
vm.getLocations = function(id) {
console.log("Functional org ID:" + id);
locationRepository.getLocation(id).then(function (results) {
vm.locations = results;
}, function (error) {
vm.error = true;
vm.errorMessage = error;
});
}
Assuming my service layer is fine and brings back a JSON object with everything I require, what could the problem be? The vm.getLocations function is definitely getting called because my console log is being printed. The service layer is also fine because a JSON object to being logged to my command prompt.
My question is how do I populate my second drop-down from whatever JSON is returned by getLocations? Please hence I do not want to make use of $scope in Angular.
The "ng-controller" attribute is repeated on each select. Put the attribute only one time on a parent element!
<div data-ng-controller="addAssetController as addAssetCtrl">
<!-- Drop Down 1 and 2 here -->
</div>
If you dont share scope you can't do what you want to do. Meaning if you dont have a parent vm or pass something to your directive = you can't tell what is selected.
Pull up your controller a level and share it among selected or you are going to have to either watch a shared variable in a service, or rely on $on & $broadcast to communicate.
Pretty sure that this is because they have different scopes and different controllers.
Assuming that the actual HTML looks like the following:
<select data-ng-controller="addAssetController as addAssetCtrl" id="location" data-ng-model="addAssetFormCtrl.location.id">
<option data-ng-repeat="location in addAssetCtrl.locations | orderBy:'id' track by $index" value="{{location.id}}">
{{location.id}} - {{location.address6}}
</option>
</select>
<select data-ng-controller="addAssetController as addAssetCtrl" id="functionalOrg" data-ng-model="addAssetFormCtrl.functionalOrg.id" ng-change="addAssetCtrl.getLocations(addAssetFormCtrl.functionalOrg.id)">
<option data-ng-repeat="functionalOrg in addAssetCtrl.functionalOrgs | orderBy:'id' track by $index" value="{{functionalOrg.id}}">
{{functionalOrg.id}} - {{functionalOrg.account}}
</option>
</select>
Then, to the best of my knowledge, each select will get a different instance of the controller, each with different scopes. So you've effectively got a controller addAssetCtrl1 and addAssetCtrl2, so setting data on 1 does not set it on 2.
The solution would be to set the data on a parent controller, or, probably more simply, to do the following:
<div data-ng-controller="addAssetController as addAssetCtrl">
<select id="location" data-ng-model="addAssetFormCtrl.location.id">
<option data-ng-repeat="location in addAssetCtrl.locations | orderBy:'id' track by $index" value="{{location.id}}">
{{location.id}} - {{location.address6}}
</option>
</select>
<select id="functionalOrg" data-ng-model="addAssetFormCtrl.functionalOrg.id" ng-change="addAssetCtrl.getLocations(addAssetFormCtrl.functionalOrg.id)">
<option data-ng-repeat="functionalOrg in addAssetCtrl.functionalOrgs | orderBy:'id' track by $index" value="{{functionalOrg.id}}">
{{functionalOrg.id}} - {{functionalOrg.account}}
</option>
</select>
</div>

How to use a select option dropdown in an Angular Directive?

Plunkr: http://plnkr.co/edit/pJRzKn2v1s865w5WZBkR?p=preview
I have 2 forms, a simple and advanced form.
Both have the same options (a lot of options)
Only a couple of differences in the opening select tag which contains
<select ng-show="showSimpleSelect"
ng-model="selected_tag"
ng-change="changeFormTag(formData)"
class="form-control manage-source-input-tag">
<!-- if advanced then -->
<select ng-show="showAdvanceSelect"
ng-model="formData.tag"
ng-change="changeTag(formData.tag)"
class="form-control manage-source-input-tag">
<option value="brand">Brand</option>
<option value="client">Client</option>
<option value="companies">Companies</option>
...
</select ng-show="showSimpleSelect">
</select ng-show="showAdvanceSelect">
In my Directives Controller, I'm using vars like this to show and hide the opening select tags:
vs.showSimpleForm = function() {
vs.showSimpleSelect = true,
vs.showAdvanceSelect = false,
However the HTML ends up looking like this, which breaks the design:
How would you go about refactoring this?
Angular overrides the select tag as a custom directive that expects an ng-options attribute instead of option tags. You can just hard-code your options into an array and put that as the ng-option
//controller
$scope.options = ["brand", "client", "companies"];
//html
<select ng-show="showAdvanceSelect"
ng-model="formData.tag"
ng-change="changeTag(formData.tag)"
ng-options="option for option in options"
class="form-control manage-source-input-tag">

How do I get the ng-model of a select tag to get the initially-selected option?

I'm pretty new to Angular, so I may be going about this all wrong...
I have a <select> similar to the following:
<select ng-model="mySelectedValue">
<option value="">--</option>
<option ng-repeat="myValue in someDynamicArrayOfValues" value="{{myValue}}" ng-selected="myFunctionForDeterminingWhetherValueIsSelected(myValue)">{{myValue}}</option>
</select>
This mostly works... The dropdown initially renders with the correct option selected, and if I change the selected option, then mySelectedValue will get the new selection. However, mySelectedValue does NOT get the initially-selected option. mySelectedValue is blank until I change the value in the dropdown.
I looked at ng-init, but that seems to get evaluated before someDynamicArrayOfValues is set...
Is there a way I can get mySelectedValue to receive the value in the initially-selected <option>?
UPDATE:
I forgot to mention that I had also tried using ng-options, but haven't had any luck getting that to work in conjunction with determining which option was selected.
I've tried this:
<div ng-show="someDynamicArrayOfValues">
<select ng-model="mySelectedValue" ng-options="arrayValue for arrayValue in someDynamicArrayOfValues" ng-selected="myFunctionForDeterminingWhetherValueIsSelected(arrayValue)">
<option value="">--</option>
</select>
</div>
and this:
<div ng-show="someDynamicArrayOfValues">
<select ng-model="mySelectedValue" ng-options="arrayValue for arrayValue in someDynamicArrayOfValues" ng-init="myFunctionForSettingSelectedValue()">
<option value="">--</option>
</select>
</div>
but neither of those work because the select is built (and ng-init and ng-selected both get evaluated) before someDynamicArrayOfValues has been set and, therefore, before the <select> is even visible. When using <option ng-repeat="...">, the <select> doesn't get built/initialized until after someDynamicArrayOfValues is set, which is why I had been going that direction.
Is there a way to get the ng-options technique to work while, at the same time, having the select dependent on someDynamicArrayOfValues (if ng-options is the better way to go)?
UPDATE 2:
Here's a Plunker (modified from ababashka's answer) that is a little closer to what I'm ultimately trying to achieve: http://plnkr.co/edit/Kj4xalhI28i5IU0hGBLL?p=preview. It's not quite there yet... I'd like it to have each of the 3 dropdowns set with the closest-matching dynamic value once someDynamicArrayOfValues is set.
I think that it will be good it you will use ng-options attribute of select tag. It's an angular directive which creates options according to Array of options. You can take a look at select documentation
If you use your code - your function myFunctionForDeterminingWhetherValueIsSelected works twice for every option at initialization and once for every option item when you select some another option.
Demo with your code: http://plnkr.co/edit/0IVNLHiw3jpz4zMKcB0P?p=preview
Demo for select you could see at description of select directive.
Update
At first, to see when value is changed - you need to use ng-change attribute of select tag, like this:
<select ng-model="mySelectedValue"
ng-options="myValue for myValue in someDynamicArrayOfValues"
ng-change="myFunctionForDeterminingWhetherValueIsSelected()">
<option value="">--</option>
</select>
Then, i don't know how does myFunctionForSettingSelectedValue look like, but there are 2 variants:
This function returns some value - then you need to use ng-init next way.
Controller:
$scope.someInitFunc = function () {
return 'One';
};
HTML:
<select ng-model="mySelectedValue"
ng-options="myValue for myValue in someDynamicArrayOfValues"
ng-change="myFunctionForDeterminingWhetherValueIsSelected()"
ng-init="mySelectedValue = someInitFunc()">
<option value="">--</option>
</select>
You set value of mySelectedValue in this function - then you do this.
Controller:
$scope.someInitFunc = function () {
$scope.mySelectedValue = 'One';
};
HTML:
<select ng-model="mySelectedValue"
ng-options="myValue for myValue in someDynamicArrayOfValues"
ng-change="myFunctionForDeterminingWhetherValueIsSelected()"
ng-init="someInitFunc()">
<option value="">--</option>
</select>
I have created an example which implements the first version of using ng-init. When new value is selected - it's printed to console.
Also, i moved options to the options.json file. So options are initialized just after ajax request was finished. Everything works great.
Demo: http://plnkr.co/edit/pzjxxTnboKJXJYBGcgNb?p=preview
Update 2
Hello again. I think you don't need to have any ng-init according to your requirements. You can just initiate values of your model when http request is finished. Also i don't understand why do you need ng-change function in this case.
Here is modified code you need from your plunk where values of ng-models are initiated after options are loaded.
JavaScript:
.controller('MainCtrl', function($scope, $http) {
$scope.someStaticArrayOfValues = ['One', 'Two', 'Three'];
$scope.mySelectedValues = {};
$http.get('options.json').then(
function (response) {
$scope.someDynamicArrayOfValues = response.data;
for (var i = 0; i < $scope.someStaticArrayOfValues.length; ++i) {
$scope.someDynamicArrayOfValues.some(function (value) {
if (value.substring(0, $scope.someStaticArrayOfValues[i].length) === $scope.someStaticArrayOfValues[i]) {
$scope.mySelectedValues[$scope.someStaticArrayOfValues[i]] = value;
return true;
}
});
}
},
function (response) {
console.log('ERROR!');
}
);
});
HTML:
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div ng-show="someDynamicArrayOfValues">
<ul>
<li ng-repeat="staticValue in someStaticArrayOfValues">
{{staticValue}} -
<select ng-model="mySelectedValues[staticValue]"
ng-options="myValue for myValue in someDynamicArrayOfValues">
<option value="">--</option>
</select>
<h2>{{mySelectedValues[staticValue]}}</h2>
</li>
</ul>
</div>
</body>
Demo: http://plnkr.co/edit/9Q1MH0esGE1SIJa0m2NV?p=preview
Here is a modified plunker that works as intended: http://plnkr.co/edit/Y8OSvmrG3u0XjnCU3ah5?p=preview.
The main change was using ng-if in place of ng-show. This forces angular to recompile/link the html whenever it is rendered:
<div ng-if="someDynamicArrayOfValues">
...
</div>
Also ng-change, from the original plunker, shouldn't be necessary, and there were a couple of typos fixed.
It works a whole lot better when you use ng-options on your select element instead of nesting option with ng-repeat.
https://docs.angularjs.org/api/ng/directive/select
Then you are capable of setting the ng-model with ng-init.
You can try to set the initial value of mySelectedValue in your Controller like so:
$scope.mySelectedValue = '';
I have created example for your problem in plnkr.
Visit: plnkr.co/edit/rKyjijGWSL1IKy51b8Tv?p=preview
You are going about it the reverse way. ng-model reflects the state of the <select> and is two-way bound.
You just need to set your mySelectedValue to what you want <select> to select first, and no other tricks are required.
So, in the controller, do something like the following:
$scope.mySelectedValue = someDynamicArrayOfValues[0];
And remove the ng-selected and the <option ng-repeat...> from <select>:
<select ng-model="mySelectedValue"
ng-options="value for value in someDynamicArrayOfValues">
<option value="">--</option>
</select>

Resources