I have a directive when given an array it creates check boxes for that list of items using the Name as the label for the checkbox.
Html
<div>
<a style="float:right; margin-bottom: 5px;" ng-click="selectNone()" href="#">Select None</a>
<a style="float:right; margin-bottom: 5px;margin-left: 10px" ng-click="selectAll()" href="#">Select All</a>
<div class="cleared"></div>
<div class="form-input form-list">
<label ng-repeat="item in valuelist | orderBy:'Name'">
<input type="checkbox" checklist-model="model" checklist-value="item" /> {{item.Name}}<br />
</label>
</div>
JS
'use strict';
growllApp.directive('checkboxlist', [function () {
return {
restrict: 'E',
templateUrl: 'scripts/modules/checkboxlist.template.html',
controller: 'checkboxlistController',
scope: {
model: "=",
value: "=",
valuelist: "="
}
}
}]);
growllApp.controller('checkboxlistController', ['$scope', '$routeParams', '$location', '$cookieStore', function ($scope, $routeParams, $location, $cookieStore) {
$scope.selectAll = function () {
$scope.model = angular.copy($scope.valuelist);
};
$scope.selectNone = function () {
$scope.model = [];
};
}]);
Using the directive
<checkboxlist ng-show="applyToProducts" model="coupon.Products" value="Name" valuelist="productsList"></checkboxlist>
All this works fine in most scenarios. However, I have a scenario where the array I'm passing in has objects in it that do not have the property "Name" but instead have the property "Title".
How do I use the attribute I have in the directive called "value" for the part that determines the label.
So in the directive html instead of saying {{item.Name}} how can I specify {{item.Title}} by passing in that the property name is title in certain cases?
You can change the 'value' attribute of your directive to '#' (it means the value will be sent as a string to your directive. You can read more in this article )
scope: {
model: "=",
value: "#",
valuelist: "="
}
and to get the object's property, you can do:
{{item[value]}}
In addition to the answer suggesting a ternary operator you could simplify that to be something like
{{ item.Name || item.Title }}
and you could have as many alternatives as you need.
However, a more robust approach I think would be to do like someone else suggested and say
scope : {
...
key:'#'
...
}
where key is the name of the property and the access it like
{{ item[key] }}
You could try using a ternary operator:
{{ item.Name ? item.Name : item.Title }}
You would probably need to use a custom comparator for the orderBy then.
Related
I have a directive (element) that I created for a "switch", that uses input[checkbox].
As long as the initial state of the checkbox is to be NOT checked, everything works fine. But if I want to set the initial state to checked (based on my controller value), then it's always the opposite. Why is the value not checked when the controller variable says it should be?
Html
<a-switch toggle-state="vm.doSomething"></a-switch>
Directive Html
<div class="switch-container">
<input type="checkbox" id="switch" />
<label for="switch" class="pm-switch"></label>
</div>
Javascript controller
vm.doSomething = {
state: true
};
Directive
angular.module('material')
.directive('aSwitch', [
'$timeout', function($timeout) {
return {
templateUrl: 'elements/material/switch/switch.html',
transclude: false,
restrict: 'E',
scope: {
toggleState: '=',
},
link: function (scope, element) {
element.on('click touchstart', function (event) {
if (event.srcElement && event.srcElement.id && event.srcElement.id === "switch") {
event.stopPropagation();
$timeout(function() {
scope.toggleState.state = !scope.toggleState.state;
});
}
});
}
};
}
]);
I realize that in order to set the checked state of a generic
<input type="checkbox" />
I just need to add the attribute "checked", like
<input type="checkbox" checked />
but how do I do that if it's inside my directive's html?
As you are using isolated scope which has scope: { toggleState: '='} in it, you should have directly bind that toggleState.state to the input box inside template, so that the link function code will get remove as toggleState has been two way binded with your controller scope variable using toggle-state attribute
Directive.html
<div class="switch-container">
<input type="checkbox" id="switch" ng-model="toggleState.state"/>
<label for="switch" class="pm-switch"></label>
</div>
I am new to Angular and I have this issue that I don't get solved. I have read today alot about good style and $scope soup but I could not find an answer to this.
It is the following, very easy example:
I have a controller with an ng-repeat inside and an input with a change-event.
<div id="searchbar" data-ng-controller="SearchCtrl">
<input id="search" autocomplete="off" data-ng-model="search" data-ng-keyup="getResults( search );" />
<div id="input_results">
<li data-ng-repeat="x in names">
{{ x.Country }}
</li>
</div>
</div>
When I assign some json directly from the controller function everything works fine.
var app = angular.module("myApp", []);
var SearchCtrl = function($scope, $http, HTTPService) {
console.log("Control opened");
$scope.names = [{
"Country": "TEXT"
}];
};
When I try to assign json out of the event, then I receive there "parent is null"
var app = angular.module("myApp", []);
var SearchCtrl = function($scope, $http, HTTPService) {
var _this = this;
console.log("Control opened");
$scope.getResults = function(searchstring) {
console.log("Execute search: " + searchstring);
$scope.names = [{
"Country": "TEXT"
}];
_this.getResults(searchstring, $scope, $http);
};
};
I don't know how I can pass the correct scope to getResults() or how to solve this issue. Additionally I have read that it is best to use dots in model names like SearchStrl.search to avoid shadowing.
I am also confused about the behaviour, when I change $scope.search it works fine inside the getResult() function, but why not with the ng-repeat.
It would be nice if somebody could explain me the reason for this behaviour.
Thank you.
Your ng-repeat code fails to work because he doesn't has an array to repeat on through.the code only creates the array after you activated 'getResults' function.
in your controller you shold have something like this:
app.controller('CTRL1', function($scope){
$scope.names = [{
"Country": "TEXT"
}]; //your array
$scope.getResults = function(search) {
//your search code.
}
})
I can see you're trying to make a list of items with a search. instead of the above code I will suggest you do as followed:
<div data-ng-controller="SearchCtrl">
<input data-ng-model="search" /> <!-- creates a search instance- -->
<div id="input_results">
<!--filter by search model -->
<li data-ng-repeat="x in names | filter: search">
{{ x.Country }}
</li>
</div>
and in your code:
$scope.names = [{
"Country": "TEXT"
}];
I am creating reusable custom directive in angularjs where I am looking to pass fieldName for ng-repeate items as attribute. All my scope is isolated
My part of directive codes as below
<div class="list">
<label ng-repeat="item in items" class="item item-text-wrap">
{{item.City}}
</label>
</div>
In above code I am passing fieldName hard code but I want to pass City (i.e. field name) by attribute
of my custom directive
<custom-select items="deptStations" drop-down-field="City"></custom-select>
in above items are passed by http service from controller
.controller('Ctrl', function($scope, $http) {
$http.get("http://www.xxxx.com/_api/lists/getbytitle('XXX')/items?$select=Id,City_Code,City&$filter=Active eq 1&$orderby=City asc", {
headers: {
Accept : "application/json;odata=verbose"
}
}).then(function(resp) {
$scope.deptStations = resp.data.d.results;
}, function (err) {
console.log(err);
});
});
So idea over here is that I want to pass drop-down-field and I want to pass in my directive. Is it possible, if yes then how ?
i think below code will solve your problem
angular.module("module").directive("customSelect", function(){
return{
scope : {
dropDownField : '#',
items : '='
};
};
});
<div class="list">
<label ng-repeat="item in items" class="item item-text-wrap">
{{item[dropDownField]}}
</label>
</div>
As an example of what I want, consider the following example
<select ng-options="option.text for option in options"></select>
In my directive I want to use something similar to ngOptions, because I need to create a list
For example, assume I have a directive barFoo, called as follows:
<bar-foo options="options"></bar-foo>
with a template/html as follows:
<ol>
<li ng-repeat="option in options" ng-bind="option.text"></li>
</ol>
What is needed to change all this into a call like
<bar-foo options="option.text for option in options"></bar-foo>
The main reason I need this is because I don't know the property name holding the label text (in this case it is text)
I provided a fiddle and see whether this helps. Instead of passing in "options.text for option in options", I set it up such that you pass the "options" array and then the field you want. I assumed the field will be set up as a variable; if it hard-coded, then you can just do field='someFieldName' instead.
http://jsfiddle.net/y376K/1/
HTML
<body ng-app='testApp'>
<div ng-controller='TestCtrl'>
<bar-foo options='options' field='{{optionsField}}'></bar-foo>
</div>
</body>
JS
angular.module('testApp', [])
.controller('TestCtrl', function($scope) {
$scope.options = [
{
text: 'Node.js rocks my socks',
language: 'Node.js',
},
{
text: 'Angular is hot',
language: 'Angular.js',
},
{
text: 'Backbone.js is mmmm',
language: 'Backbone.js',
}
];
$scope.optionsField = 'text';
})
.directive('barFoo', function() {
return {
restrict: 'E',
scope: {
options: '=',
field: '#'
},
template: '<ol><li ng-repeat="option in options" ng-bind="option[field]"></li>'
};
})
You can do this by parsing the attribute. The other solution would be to pass it as two attributes (see the other answer)
You should probably use a regexp for this, but I coded this quickly:
app.directive('barFoo',function($parse) {
return {
restrict: 'E',
scope: {},
templateUrl: "template.html",
link: function(scope,element,attrs) {
var splitOptions = attrs.options.split(' for ');
scope.fieldName = splitOptions[0].split('.')[1];
var repeatExp = splitOptions[1];
scope.valueName = repeatExp.split(' in ')[0];
var collectionName = repeatExp.split(' in ')[1];
scope.values = $parse(collectionName)(scope.$parent);
}
};
});
See this plnkr
I am trying create a wrapper directive over select and I am trying to assign the 'name 'attribute to the select
directive
<form name=myform>
<selectformfield label="Select Orders" id="id_1" name="orderselection"
selectedval="obj.order" options="Orders" />
</form>
I have my directive defined as
mainApp
.directive(
'selectformfield',
function() {
return {
restrict : 'E',
transclude : true,
scope : {
label : '#',
id : '#',
selectedval : '=',
options : '=',
name: '='
},
template : "<select class='form-control' ng-model='selectedval' name='{{name}}' ng-options='item as item.name for item in options' required><option value=''>-- select --</option></select>"
};
});
I am trying to access the select's name attribute through myform in the controller something like console.log($scope.myForm.orderselection) and I get undefined
If I hardcode the name in the directive then I am able to access the attribute console.log($scope.myForm.orderselection)
I am missing anything here. Do I have to do any post compile or something ?
Khanh TO is correct in that you need to setup your name correctly when trying to access to through your isolated scope. Here is a working example of what I believe you are trying to accomplish. I've added comments to the code where I've changed what you had.
plunker
Javascript:
var app = angular.module('plunker', [])
.controller('MainCtrl', function ($scope, $log) {
$scope.model = {
person: {
name: 'World'
},
people: [{
name: 'Bob'
}, {
name: 'Harry'
}, {
name: 'World'
}]
};
})
.directive('selectformfield', function ($compile) {
return {
restrict: 'E',
replace: true, // Probably want replace instead of transclude
scope: {
label: '#',
id: '#',
selectedval: '=',
options: '=',
name: '#' // Change name to read the literal value of the attr
},
// change name='{{ name }}' to be ng-attr-name='{{ name }}' to support interpolation
template: "<select class='form-control' ng-model='selectedval' ng-attr-name='{{name}}' ng-options='item as item.name for item in options' required><option value=''>-- select --</option></select>"
};
});
HTML:
<body ng-controller="MainCtrl">
<p>Hello {{ model.person.name}}!</p>
<form name='myForm'>
<label for='orderselection'>Say hello to: </label>
<selectformfield label="Select Orders" id="id_1" name="orderselection"
selectedval="model.person" options="model.people"></selectformfield>
<p ng-class='{valid: myForm.$valid, invalid: myForm.$invalid }'>The form is valid: {{ myForm.$valid }}</p>
<p ng-class='{valid: myForm.orderselection.$valid, invalid: myForm.orderselection.$invalid }'>The people select field is valid: {{ myForm.orderselection.$valid }}</p>
</form>
</body>
CSS:
.valid {
color: green;
}
.invalid {
color: red;
}
Accessing the DOM directly in $scope is bad practice and should be avoided at all costs. In MVC structure like angular, instead of accessing the DOM (view) to get its state and data, access the models instead ($scope). In your case, you're binding the name of your directive to the orderselection property of your parent scope. Also notice that a form is an instance of FormController. The form instance can optionally be published into the scope using the name attribute. In your case, you create a new property on the parent scope.
You could try accessing the name like this if you're in your parent scope:
console.log( $scope.myform.orderselection );
Or if you're in your directive scope.
console.log( $scope.name);
Because your scope directive name property binds to your parent scope orderselection property, you need to assign a value to your parent scope property or it will be undefined. Like this:
$scope.myform.orderselection = "orderselection ";
If you need to do validation inside your directive, since you already bind the name attribute with the orderselection. You could do it like this:
template : "<select class='form-control' ng-attr-name='{{name}}' ng-disabled='[name].$invalid' .../>