I have a select box with a blank option and some other options. The options are not generated with ngOptions directive, because they are generated on server side (with Symfony forms).
In some cases I want to unselect the selected value of the select box. So that the blank option is selected. But I cannot get this to work. The select box does not get updated.
I have created a jsfiddle to show the problem.
html
<div ng-controller="MyCtrl">
<form name="form">
<select ng-model="foo.hero" name="foo[hero]" my-directive="">
<option value=""></option>
<option value="1">Batman</option>
<option value="2">Superman</option>
<option value="3">Spiderman</option>
</select>
</form>
<p>Selected: {{ foo.hero }}</p>
</div>
javascript
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.foo = {hero: '2'};
}
myApp.directive('myDirective', function($timeout) {
return {
require: ['ngModel', '?form'],
link: function(scope, element, attrs, ctlrs) {
$timeout(function() {
var modelController = ctlrs[0];
modelController.$setViewValue('');
});
}
};
});
Use modelController.$render() after you call $setViewValue. This will update the DOM element(s).
myApp.directive('myDirective', function($timeout) {
return {
require: ['ngModel', '?form'],
link: function(scope, element, attrs, ctlrs) {
$timeout(function() {
var modelController = ctlrs[0];
modelController.$setViewValue('');
modelController.$render();
});
}
};
});
Updated fiddle here.
Do this:
$timeout(function() {
scope.foo.hero = '';
});
since the model of your select is foo.hero whenever you change it then the select will change the selected.
Not sure why you need to muck around with modelController? Can't you just update the model to the default value?
myApp.directive('myDirective', function($timeout) {
return {
scope: {
model: '=?ngModel'
},
link: function(scope, element, attrs, ctlrs) {
$timeout(function() {
scope.model = '';
});
}
};
});
Updated fiddle here.
Related
<div ng-app="myApp" ng-controller="myCtrl">
<select ng-model="selectedName" ng-options="x for x in names" multiple>
</select>
<input value="{{selectedName[0]}}">
</div>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.names = ["Emil", "Tobias", "Linus"];
});
As you can see I have a select that should update the input value when clicking on an option, and it works, but when I erase some text from the input and click on an option it won't update the input value anymore.
Note: when i check the html in the inspector the value attribute is updated but not visually in the input element
Is there any explanation or solution to this?Thanks.
I would recommend to not use $scope object in your project but just to quick resolve your issue. There is plenty way to achieve it for example you can use ng-change directive. Instead of value attribute use ng-model directive. As I see select has multiply attribute use join() inside ng-change fn to change array to a string with multiply values.
<div ng-app="myApp" ng-controller="myCtrl">
<select ng-change="update(selectedName)" ng-model="selectedName"
ng-options="x for x in names" multiple>
</select>
<input ng-model="selected">
</div>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.names = ["Emil", "Tobias", "Linus"];
$scope.update = function(value) {
$scope.selected = value.join();
};
});
You can use same ng-model on the input element to maintain bidirectional communication between the select and input elements.
However since you use multiple directive on the select element, the selected model value is saved as an array, while the value entered manually in the input is saved as a string.
You can overcome this issue by adding a directive to the input element that parses the model value to an array, here is the example:
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<select ng-model="selectedName" ng-options="x for x in names" multiple></select>
<input ng-model="selectedName" to-array>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.names = ["Emil", "Tobias", "Linus"];
});
app.directive('toArray', function(){
return{
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
function toArray(viewValue){
return viewValue && viewValue.split(',');
}
ctrl.$parsers.unshift(toArray);
}
};
});
</script>
probably you are trying to select the same range of items starting from THE SAME value. In your example you try to show exclusively first selected item.
change:
<input value="{{selectedName[0]}}">
into:
<input value="{{selectedName}}">
seems to be working fine. For this example I would recommend using: ui-select
Can someone show me how to gather the value select on.change of the dropdown box and then use that value as a varible in my controller.
for some reason the $ColorPicked varible will not revolve in the $scope.base = response.data.type.$ColorPicked; BUT if i just remove the $ColorPicked and type in Red it works no problem.
I am still very new to Angular and JS for that matter so please excuse my stupidity. I have Googled and Googled for a clear cut answer and I got nothing.
INDEX.HTML
<h3>Color:</h3>
<select class="formBoxes" id="ColorPicked">
<option value="Red">Redd</option>
<option value="Blue">Blue</option>
<option value="Green">Green</option>
</select>
SCRIPT.JS
$ColorPicked = "Red";
var app = angular.module("computer",['ngRoute'])
.config(['$routeProvider', function($routeProvider){
$routeProvider.
when('/main',{
templateUrl: 'archetype.html',
controller:'MainCtrl'
}).
otherwise({redirectTo:'/main'})
}])
.controller('MainCtrl', ['$scope', '$http', function($scope, $http){
$http.get('archetype.json').then(function(response){
$scope.base = response.data.type.$ColorPicked;
;
});
}]);
you need to use ng-model to bind the selected value to the controller's property. If you want to initialize the select input to a value on the model, then you need to use ng-options
<select ng-model="selectedColor"
ng-options="opt.value as opt.label for opt in opts">
</select>
and in your controller you would have the following on your scope:
$scope.opts = [
{ value:'red', label:'Red' },
{ value:'blue', label:'Blue' },
{ value:'green', label:'Green' },
]
$http.get(...).then( function( response ){
$scope.selectedColor = response.data.type.$colorPicked;
})
There are two things,
(i)You need to have a $scope variable defined for the ColorPicked inorder to provide the default selection.
(ii)You need to have ng-model which gets bind to the variable. Pass the selected Color to the function using the ng-change directive
HTML:
<select ng-model="ColorPicked" ng-change="setItem(ColorPicked)">
<option>Red</option>
<option>Blue</option>
<option>Green</option>
</select>
Controller:
function MyCtrl($scope) {
$scope.ColorPicked = "Red";
$scope.setItem = function(opt) {
$scope.base =opt;
}
}
DEMO
Working Demo for your requirement
I'm trying to create an AngularJS Directive to manage the promps of a <select> input. The 3 different modes are as follows:
Don't allow a blank option
This is the default behavior
Allow a blank option with no text
Achieved by setting allow-blank="true" on the directive
Allow a blank option with prompt text
Achieved by setting allow-blank to any value other than "true"
However, the blank options are never available.
Demo on Plunker
Template
<select ng-options="tag.id as tag.name for tag in myTags">
<option ng-if="allowBlank === 'true'" value=""></option>
<option ng-if="allowBlank && allowBlank !== 'true'" value="">{{allowBlank}}</option>
</select>
Directive
myApp.directive('mySelector', ['$http', function($http) {
return {
templateUrl:'my-selector-template.html',
restrict: 'E',
scope: {
allowBlank: '#?'
},
replace: true,
controller: function ($scope) {
$scope.myTags = [
{"name":"aliquam in","id":1},
{"name":"massa velit","id":2},
{"name":"nec vestibulum","id":3}
];
}
};
}]);
The problem is that the content of the select is transcluded (see below). If you inspect the elements that are output you don't even see the option tags you defined inside.
As you're just using a string you should use a pre-linking function where you add the correct option in via javascript. The following code should do the trick (Forked Plunk).
link: {
pre: function(scope, element, attrs){
if(attrs.allowBlank === 'true') element.append('<option value=""></option>');
else if(attrs.allowBlank && attrs.allowBlank !== '') element.append('<option value="">' + attrs.allowBlank + '</option>');
}
}
EDIT The select does not 'transclude' it's contents, as #lightswitch05 pointed out the select directive grabs the first child with value="" as the empty node (source ref). Then later it clears out the contents of the select and dynamically adds in the relevant <option> tags (source ref)
I am creating dropdown in a directive as follows:
<select ng-model="selectedSite">
<option value="new">Add New Site</option>
<option value="line" disabled>------------------------</option>
<option ng-repeat="site in defaultSites"
value="{{$index}}">
{{site.name}}
</option>
</select>
Directive is:
app.directive('siteForm', function() {
return{
restrict: 'E',
replace: true,
scope: {
site: '=',
defaultSites: '=',
selectedSite: '=',
},
templateUrl: '/views/templates/site_form.html',
link: function($scope, element, attrs) {
$scope.$watch('selectedSite', function(newValue, oldValue) {
console.log('Site selected:', newValue);
if (newValue !== undefined && newValue !== null) {
if (newValue !== "new") {
var value = $scope.defaultSites[parseInt(newValue)];
$scope.site.name = value.name;
} else {
$scope.site.name = "";
}
}
});
}
};
});
However when I provide the initial index in selectedSite, it does not work and always shows first option. E.g. If we provide the selectedSite as "1" then option with value "1" should get selected which is not happening.
Everything else works fine including $watch and selectedSite gets populated when I select option from dropdown.
I am using AngularJS v1.2.10.
Try to use ng-selected in following way
<option ng-repeat="site in defaultSites" value="{{$index}}" ng-selected="{{$index == selectedSite}}">
{{site.name}}
</option>
Try calling $scope.$apply() at the end of your $watch handler.
See the AngularJS docs on Scope.
I build this directives for AngularJS+Symfony2 project:
app.directive('country', ['$http', function($http) {
return {
restrict: "C",
link: function(scope, element, attrs) {
$http.get(Routing.generate('countries')).success(function(data) {
if (data.message) {
scope.message = data.message;
} else {
scope.countries = data.entities;
}
}).error(function(data, status, headers, config) {
if (status == '500') {
scope.message = "There is not connection with server";
}
});
}
};
}]);
app.directive('state', ['$http', '$parse', function($http, $parse) {
return {
restrict: "C",
link: function(scope, element, attrs) {
scope.$watch(attrs.trigger, function() {
state = $parse(attrs.trigger)(scope);
iso = state != undefined && state.iso_country != undefined ? state.iso_country : state;
if (iso !== undefined && iso !=='') {
$http.get(Routing.generate('states') + '/' + iso).success(function(data) {
if (data.message) {
scope.message = data.message;
} else {
scope.states = data.entities;
}
}).error(function(data, status, headers, config) {
if (status == '500') {
scope.message = "There is not connection with server";
}
});
}
});
}
};
}]);
And this is how I use in my template file:
<select class="country"
ng-model = "country.standard_address"
ng-options = "country.name for country in countries">
<option value="-1">{{ "Select country" | trans }}</option>
</select>
<select class="state"
ng-model = "state.standard_address"
ng-disabled = "!states"
ng-options = "state.name for state in states"
trigger = "country.standard_address">
<option value="-1">{{ "Select state" | trans }}</option>
</select>
I need to add some way to validate this fields in case user didn't change it and remain with value equal -1. I could do this on click event for submit button but I not enabled the button until the form has no errors. This is the code to handle this part:
<input type="button" class="button {% verbatim %}{{ step1Form.$valid && 'active' || 'gray'}}{% endverbatim %}" value="Continuar" ng-disabled="!step1Form.$valid" ng-click="nextStep(2)" />
how I can do this?
Quoting the docs on select (with ngOptions):
Optionally, a single hard-coded element, with the value set to an empty string, can be nested into the element. This element will then represent the null or "not selected" option.
You need to set the value of the hard-coded option to an empty string and add the required attribute to the select elements. This way, the step1Form will not be valid unless an option (other than the null option) is selected.
UPDATE:
Seems like I misunderstood yur requirements. In order to be able to display a message on blur, you can use ng-focus and ng-blur to set the value of a variable. Then have an element that is shown/hidden based on the value of that variable (also taking into account the validity of the select).
The code for the "country" select could look like this:
<select name="countrySelect" ng-model="country.standard_address"
ng-options = "country.name for country in countries"
ng-focus="countryFocused=true" ng-blur="countryFocused=false"
required>
<option value="">Select country</option>
</select>
<div ng-hide="countryFocused || step1Form.countrySelect.$valid">
ERROR !!! Select a country ASAP !
</div>
See, also, this (updated) short demo.