How to add conditionally attribute in angularjs?
For example I only want to set the multiple attribute on a <select> if my component has a binding set to true. This means if the binding is not given the multiple attribute should not exist on my <select>.
The only solution I found was with ng-if.
You can achieve this by implementing a directive (aka ng-multiple) to handle the property multiple of the select element. The following snippet implements this solution. However, you may want to control the state of your model inside this directive, once the multiple prop will produce an array of selected values, the non-multiple will produce a single object, so this may cause an issue when switching between multiple and non-multiple.
angular.module('myApp', [])
.directive('ngMultiple', function () {
return {
require: ['select', '?ngModel'],
restrict: 'A',
scope: {
multiple: '=ngMultiple'
},
link: function (scope, element, attrs, ctrls) {
element.prop('multiple', scope.multiple);
scope.$watch('multiple', function (multiple) {
if(element.prop('multiple') != multiple){
// may be would be convenient change the ngModel
// to [] or {} depending on the scenario
element.prop('multiple', multiple);
}
});
}
};
})
.controller('myController', function ($scope) {
$scope.condition = true;
$scope.myOptions = [];
});
angular.element(document).ready(function () {
angular.bootstrap(document, ['myApp']);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-controller="myController">
<label>
<input type="checkbox" ng-model="condition" /> multiple?
</label>
<br>
<select ng-multiple="condition" ng-model="myOptions">
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
<option>Option 4</option>
<option>Option 5</option>
</select>
<br>
<tt>myOptions: {{ myOptions }}</tt>
</div>
if boolean condition is true then multiple, else not
<select ng-if="condition" ng-model="some.model" multiple></select>
<select ng-if="!condition" ng-model="some.model"></select>
<select ng-show="condition" ng-model="some.model" multiple></select>
<select ng-hide="condition" ng-model="some.model"></select>
controller,
$scope.condition = true
Related
This question already has answers here:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
(3 answers)
Closed 4 years ago.
I am trying to create a custom directive to render dropdown(select).
app.directive("uiDropdown", function () {
return {
restrict: "E",
replace: true,
scope: {
'model': '=ngModel',
'readOnly':'=?'
},
templateUrl : 'template/dropdownTemplate.html',
link: function (scope, elem, attrs) {
}
};
});
the template is
<span ng-if="!readOnly">
<select ng-model="model" >
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
Html code to use the directive is
<ui-dropdown ng-model="region" read-only='readOnly'>
The plunker code is plunker
If I remove the code 'ng-if="!readOnly"' from the template file, it is working as expected. If I change from "ng-if" to "ng-show" it is working as well.
Am I missing something here? Actually, the directive is supposed to do much more functionality than the one shown in this example. I perfer to use ng-if instead of ng-show. Please help in resolving this issue.
It has to do with the fact that ng-if creates its own child scope and then you're using a primitive directly. ng-if will actually create a local model boolean that has no relation to the parent. This would be an issue with ng-if even if it weren't being used via a directive, too.
You can work around this by passing an object and reading/setting a value on that object. Here's a simple example showing that your ng-if issue is not related to the directive and then how you can fix this using an object:
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.readOnly = false;
$scope.primitive = "1";
$scope.object = {
selectedValue: "1"
};
})
.directive('uiDropdown', function() {
return {
restrict: 'E',
templateUrl: 'dropdownTemplate.html',
scope: {
model: '=ngModel',
fieldName: '#',
readOnly: '=?'
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div>
<label>Readonly: <input type="checkbox" ng-model="readOnly" /></label>
</div>
<div>
<h1>ng-if with primitive - no directive</h1>
<h2>This will not work</h2>
<div>
Value: {{ primitive }}
</div>
<div ng-if="!readOnly">
<select ng-model="primitive">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
</div>
<div>
<h1>ng-if with object - directive</h1>
<h2>This will work</h2>
<div>
Value: {{ object.selectedValue }}
</div>
<ui-dropdown ng-model="object" read-only="readOnly" field-name="selectedValue"></ui-dropdown>
</div>
<script type="text/ng-template" id="dropdownTemplate.html">
<div ng-if="!readOnly">
<select ng-model="model[fieldName]">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
</script>
</div>
ng-if contains a statement that's either true or false
Try
<ui-dropdown ng-model="region" read-only='true'>
I've created a directive to display dropdowns (form selects).
However I cannot find a way to mark the selected option.
html form
<div content-selects ng-model="ctrl.contentSelects.riskStatus" selection="oneWMS.riskStatusId"></div> <!-- oneWMS.riskStatusId -->
directive
function contentSelects(){
return {
restrict: 'AE',
templateUrl: '/app/Directives/contentSelects.tpl.html',
replace:true,
scope: {
ngModel: '=',
selection: '='
},
controller:function($scope){
},
link: function (scope, element, attrs) {
scope.selectedModel = scope.ngModel[attrs.selection];
scope.isChanged = function () {
//console.log("changed");
}
element.removeAttr('id');
}
};
}// end function contentSelects
This is where I don't understand: the directive template
<div class="input-group">
<select id="{{id}}">
<option value="model.refId" ng-repeat="model in ngModel track by model.refId" ng-model="ngModel[selection]" >{{model.value}} *** {{selection}} *** {{ngModel[selection]}}</option>
</select>
</div>
In the actual value, {{ngModel[selection]}} gives me exactly what I want (the target model row), but when tied to ng-model it doesn't retrieve anything :/
ng-model="ngModel[selection]"
What is wrong with it? Using curly brackets break it of course...
Your problem is because of ngModel included in option element. You should move it to select element.
Demo
<div class="input-group">
<select ng-model="selectedModel" >
<option ng-value="model" ng-repeat="model in ngModel">{{model}}
</option>
</select>
</div>
And also look at https://docs.angularjs.org/api/ng/directive/ngOptions
I want to populate the select dropdown from database. Right now the data is coming from scope array.
html:
<div ng-controller="DropDownController">
Country:
<select id="country" class="input-sm" name ="country" ng-model="states" ng-options="country for (country, states) in countries" drop-down required>
<option value=''>Select</option>
</select>
States: <select id="state" class="input-sm" name="state" ng-disabled="!states" ng-model="cities" ng-options="state for (state,city) in states" required>
<option value=''>Select</option></select>
City: <select id="city" class="input-sm" name="city" ng-disabled="!cities || !states" ng-model="city" required>
<option value=''>Select</option>
<option ng-repeat="city in cities" value='{{city}}'>{{city}}</option></select>
</div>
Directive:
app.directive('DropDown', function ($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
$http.get('DropDown.do').success(function (data) {
if (data) {
}
});
}
};
});
I am not sure above directive is the right way of approach for my requirement. The servlet or url is not being called when I click on the drop down option. How do I achieve the same? I am still a beginner in angular.
Directives in Angular are used when you want to more easily interact with the DOM, ajax calls have no business there. You should rather use a service or a factory to process the asynchronous request and then simply return the result in the controller for further manipulations. A promise will also be needed since we are dealing with asynchronous jobs.
'use strict';
var app = angular.module('app', []);
app.factory('countryFactory', function($http) {
var getCountries = function() {
return $http.get('ajax.php').success(function(data) {
return data;
})
}
return { getCountries: getCountries }
})
app.controller('DropDownController', function($scope, countryFactory) {
var ajaxPromise = countryFactory.getCountries();
// Promises are executed once $http is done with the asynchronous job
ajaxPromise.then(function(result) {
$scope.countries = result.data;
})
})
The server side (ajax.php) is simply returning an array, here you should replace it with whatever information from the database you are needed
<?php
echo json_encode(array(
array('id' => 1, 'name' => 'USA'),
array('id' => 2, 'name' => 'Australia'),
));
Instead of using a directive, for select and respectively option elements we can use ng-options so the view would look like this:
<div ng-controller="DropDownController">
<select ng-options="country.name for country in countries track by country.id" ng-model="selected">
</div>
check this snippet you had error in directive declaration its camel case , so it should be dropDown not DropDown!
var app = angular.module('app', []);
app.directive('dropDown', function ($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
//replace with your call
//$http.get('DropDown.do').success(function (data) {
//// if (data) {
//scope.countries = data;
//}
//});
scope.countries =
{
'USA':
{
'Alabama': ['Montgomery', 'Birmingham'],
'California': ['Sacramento', 'Fremont'],
'Illinois': ['Springfield', 'Chicago']
},
'Australia':
{
'New South Wales': ['Sydney'],
'Victoria': ['Melbourne']
}
};
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
Selected country : {{states}}
<select id="country" class="input-sm" name="country" ng-model="states" ng-options="country for (country, states) in countries" drop-down required>
<option value=''>Select Country</option>
</select>
</body>
I have written a custom directive to load 3 drop downs and handle the change event of the drop down inside the controller. On change of the dropdown value I am getting the changed value inside my controller function. I need to call my custom directive and pass the new value.
I am new to AngularJs custom directive. Please let me know how to invoke a directive from within the controller.
The view where I render the custom directive:
<div class="container">
<div class="main-header clearfix">
<div class="page-title">
<h3 class="no-margin">Search for a Host</h3>
</div>
<!-- /page-title -->
</div>
<div class="padding-md">
<div class="hostsFilters row">
<select ng-model="BU" ng-change="changeTheView()" class="form- control">
<option value="">BU</option>
<option value="1">BU1</option>
<option value="2">BU2</option>
<option value="3">BU3</option>
<option value="4">BU4</option>
</select>
<span>OR</span>
<select ng-model="Application" ng-change="changeTheView()" class="form-control">
<option value="">Application</option>
<option value="1">App1</option>
<option value="2">App2</option>
<option value="3">App3</option>
<option value="4">App4</option>
</select>
<span>OR</span>
<input type="text" class="form-text" ng-model="hostName.host_name" placeholder="Hostname">
</div>
</div>
<div class="row">
<i-data-grid></i-data-grid>
</div>
The code of my controller:
'use strict';
angular.module('angularFullstackApp')
.controller('MainCtrl', function ($scope) {
$scope.changeTheView=function(){
console.log('Came inside the Change the view function..');
//Now invoke the custom directive.
}
});
The code for my directive:
'use strict';
angular.module('angularFullstackApp')
.directive('iDataGrid', function () {
return {
templateUrl: 'app/iDataGrid/iDataGrid.html',
restrict: 'E',
link: function (scope, element, attrs) {
$(document).ready(function() {
$('#example').dataTable();
} );
}
};
});
You could take a use of attribute, & pass the values inside attribute for which you wanted to place a watch that would fire when any of the value changed
Markup
<i-data-grid watch-values="['BU', 'Application']"></i-data-grid>
Code
'use strict';
angular.module('angularFullstackApp')
.directive('iDataGrid', function () {
return {
templateUrl: 'app/iDataGrid/iDataGrid.html',
restrict: 'E',
link: function (scope, element, attrs) {
$(document).ready(function() {
$('#example').dataTable();
scope.$watch(attrs.watchValues,function(newVal, oldVal){
//newly changed value available here with same sequence
//as you passed ['BU', 'Application'] here, it fires fn when any of value changed,
//newVal[0] contains newly changed value of BU
//& newVal[1] will contain newly changed value of Application
//call what ever code on basis of this values
},true);
});
}
};
});
I am trying to add autocomplete using angularJS and restangular.
http://plnkr.co/edit/Ud0c34afYZvHJ6ZQQX9N?p=preview
I am not sure how to add the following in order to make autocomplete work. Could someone suggest how to make this work
angular.module('emps', ['restangular']).directive('autoComplete', function($timeout) {
return function($scope, iElement, iAttrs) {
iElement.autocomplete({
source: $scope[iAttrs.uiItems],
select: function() {
$timeout(function() {
iElement.trigger('input');
}, 0);
}
});
};
});
While there's not alot of info about what you need this for, I think this could be best solved without a separate directive, using the html5 tag.
Using this requires modifying the existing index.html to contain the following.
<div ng-controller="AutoCtrls">
<input list="names" ng-model="selected">
<datalist id="names">
<option value="{{name}}" ng-repeat="name in names"></option>
</datalist>
selected = {{selected}}
</div>
For reference, the original code in index.html was
<div ng-controller='AutoCtrls'>
<input auto-complete ui-items="names" ng-model="selected">
selected = {{selected}}
</div>