Can anyone suggest me how can I display a checkbox list in angularjs
HTML:
<div ng-app="app">
<div ng-controller="TodoCtrl">
<span ng-repeat="(checkboxName, checkboxValue) in checkboxes">
{{ checkboxName }}
<input type="checkbox" ng-model="checkboxValue"/>
</span>
</div>
</div>
Javascript:
var app = angular.module('app', []);
app.controller('TodoCtrl', function($scope) {
$scope.checkboxes = {
'foo': true,
'bar': false,
'baz': true,
'baa': true
}
});
Update:
HTML:
<div ng-app="app">
<div ng-controller="TodoCtrl">
<!--<span ng-repeat="(checkboxName, checkboxValue) in checkboxes">
{{ checkboxName }}
<input type="checkbox" ng-model="checkboxValue"/>
</span>-->
<checklist checkboxes="checkboxes" on-change="checkboxInfo(name, value)"></checklist>
</div>
</div>
Javascript:
var app = angular.module('app', []);
app.controller('TodoCtrl', function($scope) {
$scope.foo = true;
$scope.bar = false;
$scope.baz = true;
$scope.baa = true;
$scope.checkboxes = {
'foo': $scope.foo,
'bar': $scope.bar,
'baz': $scope.baz,
'baa': $scope.baa
};
// Non-encapsulated activity: updates parent scope values
$scope.checkboxInfo = function(name, value) {
console.log('Checkbox "' + name + '" clicked. It is now: ' + value + '.');
$scope[name] = value;
};
// This shouldn't do anything if we delete '$scope[name] = value', since we isolated the scope:
$scope.$watchCollection('[foo, bar, baz, baa]', function() {
console.log($scope.foo, $scope.bar, $scope.baz, $scope.baa);
});
})
.directive('checklist', function($timeout) {
return {
restrict: 'E',
scope: {
checkboxes: '=', // create an isolate scope w/ 2-way binding
onChange: '&' // execute a function in the parent scope
},
template:
'<span ng-repeat="(checkboxName, checkboxValue) in checkboxes">' +
'{{ checkboxName }}' +
'<input type="checkbox" ng-model="checkboxValue" ng-change="onChange({name:checkboxName, value:checkboxValue})"/>' +
'</span>',
link: function(scope, element, attrs) {
// Add encapsulated activity as necessary
}
};
});
Related
I want to edit and save content in selected directive.The directive is populated by ng-repeat. On button click visible items should change to input field and again on click it should reverse
Directive is
.directive('component', function() {
var link = function(scope, element, attrs) {
var render = function() {
var t = scope.layouts[scope.type][attrs.indexs];
var icon = scope.layouts[scope.type][attrs.indexs];
var v = attrs.value;
if(scope.type=="edit"){
element.html('<input type="' + t + '" ng-model="vm.name" value="'+v+'">');
if(attrs.indexs==1){
element.html('<' + t + '>Save');
}}
if(scope.type=="display"){
element.html('<' + t + ' ng-model="'+v+'" >'+v+'</'+t+'>');
if(attrs.indexs==1){
element.html('<' + t + ' >Edit');
}}};
scope.$watch('type', function(newValue, oldValue) {
render();
});
};
return {
restrict : 'E',
link : link
}
});
plunker Link
Problem is on click all directive is changed to editable and vice-versa.
How can I make it work on selected set of directive
Try something like the following. It's much simpler to use a template with a directive than trying to modify the html directly.
Directive
angular.module('myApp', [])
.controller('MyController', MyController)
.directive('component', function(){
return {
template: [
'<div>',
'<span style="font-weight:bold" ng-show="!editing">{{ value }} <button ng-click="editing = true">Edit</button></span>',
'<span ng-show="editing"><input type="input" ng-model="value"><button ng-click="editing = false">Save</button></span>',
'</div>'
].join(''),
restrict: 'E',
scope: {
value: '=value'
},
link: function($scope){
$scope.editing = false;
}
}
});
HTML
<div class="col-sm-12" ng-repeat="s in vm.allCat track by $index">
<div class="col-sm-1 text-muted">Name</div>
<div class="col-sm-9 text-left">
<component value="s.name"></component>
</div>
</div>
</div>
I've forked your plunker here.
I have two tabs, each tab contains a set of thumbnails which I have set as a directive. Tab is also coming via a directive, and thumbnails too. The data to be pushed into the thumbnail is stored in an constant file. But each tabs thumbnails data is different. How do I implement that?
For setting tabs and thumbnail:
<tabset> <tab heading="{{heading.title}}" id="heading1" set-thumb="setThumbnail(arg)">
<thumbnail></thumbnail>
</tab> <tab heading="{{heading1.title}}" id="heading2" set-thumb="setThumbnail(arg)">
<thumbnail></thumbnail>
</tab> </tabset>
Thumbnail HTML:
<div class="row" style="padding: 20px;">
<div class="col-md-3" ng-repeat="data in thumbnailDetails">
<div class="thumbnail-sim">
<img src="resources/images/Sim-thumbnail.png" alt="sim"
class="thumbnail-img">
<div class="thumbnail-caption">
<div class="thumbnail-name">{{ data.name }}</div>
<div class="thumbnail-date">{{ data.time }}</div>
<div class="thumbnail-details">
{{ data.details }}
</div>
</div>
</div>
<br>
</div>
Thumbnail directive:
angular.module('thumbnailDirectiveModule', [])
.directive('thumbnail', function() {
return {
restrict: 'E',
templateUrl: 'UI/templates/thumbnail.html'
};
});
service part method:
s.getThumbnail = function(thisId){
if(thisId === 'heading1'){
return thumbnailDetails1;
}else if (thisId === 'heading2'){
return thumbnailDetails2;
}
};
Tab directive:
angular.module('tabsDirectiveModule', [])
.directive('tab', function() {
return {
restrict: 'E',
transclude: true,
template: '<div role="tabpanel" ng-show="active" ng-transclude></div>',
require: '^tabset',
scope: {
heading: '#',
id: '#',
setThumb: '&'
},
link: function(scope, elem, attr, tabsetCtrl) {
scope.active = false;
tabsetCtrl.addTab(scope, attr.id);
}
};
})
.directive('tabset', function() {
return {
restrict: 'E',
transclude: true,
scope: { },
templateUrl: 'UI/templates/tabset.html',
bindToController: true,
controllerAs: 'tabset',
controller: function() {
var self = this;
self.tabs = [];
self.addTab = function addTab(tab, id) {
tab.setThumb({arg: id});
self.tabs.push(tab);
if(self.tabs.length === 1) {
tab.active = true;
}
};
self.select = function(selectedTab) {
angular.forEach(self.tabs, function(tab) {
if(tab.active && tab !== selectedTab) {
tab.active = false;
}
});
selectedTab.active = true;
};
}
};
});
I created a custom directive for bootstrap alerts. My alerts display fine (hard code and data bind). Based on the alert type, I want display a unique header into my alert message based on the returned scope values (success, info, warning, danger). Currently I'm passing the type into <h1> but I don't want those values, they need to be custom.
<!-- data binding example -->
<trux-alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</trux-alert>
<!-- hard coded example -->
<trux-alert close="close" type="warning">This is an important warning message!</trux-alert>
Inside my directive, the scope is isolated using scope: '#' (one-way)
.directive('truxAlert', function() {
return {
scope: {
type: '#',
close: '&'
},
replace: true,
transclude: true,
template:
'<div class="alert" '+
'ng-class="[\'alert-\' + (type || \'warning\'), closeable ? \'alert-dismissible\' : null]" '+
'role="alert">'+
'<button ng-show="closeable" '+
'type="button" class="close" '+
'ng-click="close({$event: $event})" '+
'data-dismiss="alert" aria-label="Close">'+
'<span aria-hidden="true">×</span>'+
'<span class="sr-only">Close</span>'+
'</button>'+
'<h1>{{type}}</h1>'+
'<div ng-transclude></div>'+
'</div>',
link: function (scope, element, attrs) {}
}
});
This would be easier if all my values were pulled through data binding, but I need to allow for manual hard coded option. I know with one-way isolated scopes '#' I can't change these values though DOM manipulation. I can't use '=' or '&' for two-way because the values are strings.
How do I solve for this problem?
My recommendation is have one attribute for the control the open/closed state of the directive's alert and another attribute for the dismiss handler function.
angular.module("myApp").directive('truxAlert', function() {
return {
scope: {
type: '#',
dismissHandler: '&',
title: '#',
open: '='
},
replace: true,
transclude: true,
template:
'<div class="alert" ng-show="open" '+
'ng-class="[\'alert-\' + type]" '+
'role="type">'+
'<button type="button" class="close" '+
'ng-click="truxClose($event)" '+
'data-dismiss="alert" aria-label="Close">'+
'<span aria-hidden="true">×</span>'+
'<span class="sr-only">Close</span>'+
'</button>'+
'<h1>{{title+" "+type}}</h1>'+
'<div ng-transclude></div>'+
'</div>',
link: function (scope, element, attrs) {
console.log("truxAlert linking");
if (!scope.type) { scope.type="warning" }
scope.truxClose = function(event) {
console.log("truxClose "+event);
if (attrs.dismissHandler) {
scope.dismissHandler({$event: event});
return;
}
scope.open = false;
};
}
};
});
The linking function of the directive determines if the dismiss-handler attribute exists and either invokes the dismiss handler or directly closes the alert.
The DEMO PLNKR show the directive being used both with an ng-repeat directive and in a standalone manner.
Maybe, i don't understand you question.
You want to do so jsfiddle?
<form name="ExampleForm" id="ExampleForm">
<span simple="{{val}}">{{val}} - value from data-binding </span>
<br>
<span simple="valueTwo">valueTwo - hard code value</span>
</form>
And js controller
.controller('ExampleController', function($scope, $rootScope, $alert) {
$scope.val = "valueOne";})
And js directive
.directive('simple', function() {
return {
restrinct: 'A',
scope: {
simple: "#"
},
link: function(scope) {
console.log(scope.simple, typeof(scope.simple));
}
}})
UPDATED
angular.module('ExampleApp', ['use', 'ngMessages'])
.controller('ExampleOneController', function($scope) {
$scope.val = "valueOne";
$scope.$on('pass.from.directive', function(event, value) {
$scope.valFromDirective = value;
});
})
.controller('ExampleTwoController', function($scope) {
$scope.val = "valueTwo";
$scope.$on('pass.from.directive', function(event, value) {
$scope.valFromDirective = value;
});
})
.controller('ExampleThreeController', function($scope) {
$scope.val = "valueThree";
$scope.$on('pass.from.directive', function(event, value) {
$scope.valFromDirective = value;
});
})
.directive('simple', function($interval) {
return {
restrinct: 'A',
scope: {
simple: "#"
},
link: function(scope) {
var i = 0;
$interval(function() {
i++;
scope.$emit('pass.from.directive', scope.simple + i);
}, 1000);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<script src="https://cdn.rawgit.com/Stepan-Kasyanenko/use-form-error/master/src/use-form-error.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleOneController">
<h3>
ExampleOneController
</h3>
<form name="ExampleForm" id="ExampleForm">
<div simple="{{val}}">{{val}} - value from scope </div>
<div>{{valFromDirective}} - value from directive </div>
</form>
</div>
<div ng-controller="ExampleTwoController">
<h3>
ExampleTwoController
</h3>
<form name="ExampleForm" id="ExampleForm">
<div simple="{{val}}">{{val}} - value from scope </div>
<div>{{valFromDirective}} - value from directive </div>
</form>
</div>
<div ng-controller="ExampleThreeController">
<h3>
ExampleThreeController
</h3>
<form name="ExampleForm" id="ExampleForm">
<div simple="{{val}}">{{val}} - value from scope </div>
<div>{{valFromDirective}} - value from directive </div>
</form>
</div>
</div>
I have an input field that is create by the following directive:
.directive('googlePlaces', function(){
return {
restrict:'E',
replace:true,
scope: {location:'='},
template: function (elem, attrs) {
return '<div><div class="form-group" ng-class="{ \'has-error\' : '+attrs.form+'.google_places_ac.$invalid }"><label>Address*</label><input id="google_places_ac" required name="google_places_ac" type="text" class="form-control" placeholder="Address" /><p class="help-block" ng-message="required" ng-show="'+attrs.form+'.google_places_ac.$invalid">Message</p></div></div>'
},
link: function($scope, elm, attrs){
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
$scope.location = place.name + ',' + place.geometry.location.lat() + ',' + place.geometry.location.lng() + "," + place.formatted_address;
$scope.$apply();
});
}
}
})
I have been trying exhaustively to add required validation to this field, but it doesn't work. I do the same for other input fields in my HTML form and it works fine.
This is the relevant HTML:
<form name="registrationForm" ng-submit="register()" novalidate>
...
<div class="col-xs-12">
<google-places location=location form="registrationForm"></google-places>
</div>
...
I've tried many different things, scope: {location:'=', form:'='}, $compile, just adding directly the name registrationForm, or simply form. None of it worked.
I would really appreciate if someone could help me with this :)
You could do this in many ways. Here are couple of them.
1) Isolate the validation and display of messages, accessing form etc from the googlePlaces directive and have the control of it given to the consumer as it really is a consumer's concern. They can have full control over how to display, what to display and where to display. This would avoid any more responsibilities to the directive who will just be responsible for providing the place selection. Have your directive require the ng-model and specify required attribute as well.
So a rough implementation would be something like this.
.directive('googlePlaces', function() {
return {
require:'ngModel',
restrict: 'E',
replace: true,
scope: {
location: '=ngModel'
},
template: function(elem, attrs) {
return '<div><div class="form-group"><label>Address*</label><input id="google_places_ac" required name="google_places_ac" type="text" ng-model="locSearch" class="form-control" placeholder="Address" /></div><button type="button" ng-click="clear()">clear</button></div>'
},
link: function($scope, elm, attrs, ctrl) {
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
$scope.location = place.name + ',' + place.geometry.location.lat() + ',' + place.geometry.location.lng() + "," + place.formatted_address;
$scope.$apply();
});
$scope.clear = function() {
$scope.location = null;
}
}
}
});
and
<google-places name="location" ng-model=location required
ng-class="{ 'has-error' : registrationForm.location.$invalid }">
</google-places>
<span class="help-block"
ng-show="registrationForm.location.$invalid">Please specify location</span>
angular.module('app', []).directive('googlePlaces', function() {
return {
require:'ngModel',
restrict: 'E',
replace: true,
scope: {
location: '=ngModel'
},
template: function(elem, attrs) {
return '<div><div class="form-group"><label>Address*</label><input id="google_places_ac" required name="google_places_ac" type="text" ng-model="location" class="form-control" placeholder="Address" /></div><button type="button" ng-click="clear()">clear</button></div>'
},
link: function($scope, elm, attrs, ctrl) {
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
$scope.location = place.name + ',' + place.geometry.location.lat() + ',' + place.geometry.location.lng() + "," + place.formatted_address;
$scope.$apply();
});
$scope.clear = function() {
$scope.location = null;
}
}
}
});
.has-error input {
border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<div ng-app="app">
<form name="registrationForm" ng-submit="register()" novalidate>
<div class="col-xs-12">
<google-places name="location" ng-model=location required ng-class="{ 'has-error' : registrationForm.location.$invalid }"></google-places>
<span class="help-block" ng-show="registrationForm.location.$invalid">Please specify location</span>
</div>
</form>
</div>
2) You can 2 way bind the form object to the directive and control the validation and display message from there. You would need to place an ng-model on the input in order for validation to kick in properly.
.directive('googlePlaces', function() {
return {
restrict: 'E',
replace: true,
scope: {
location: '=',
form:'='
},
template: function(elem, attrs) {
return '<div><div class="form-group" ng-class="{ \'has-error\' :form.google_places_ac.$invalid }"><label>Address*</label><input ng-model="selectedLocation" id="google_places_ac" required name="google_places_ac" type="text" class="form-control" placeholder="Address" /><p class="help-block" ng-message="required" ng-show="form.google_places_ac.$invalid">Message</p></div></div>'
},
link: function($scope, elm, attrs) {
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
$scope.location = place.name + ',' + place.geometry.location.lat() + ',' + place.geometry.location.lng() + "," + place.formatted_address;
$scope.$apply();
});
}
}
});
angular.module('app', []).directive('googlePlaces', function() {
return {
restrict: 'E',
replace: true,
scope: {
location: '=',
form: '='
},
template: function(elem, attrs) {
return '<div><div class="form-group" ng-class="{ \'has-error\' :form.google_places_ac.$invalid }"><label>Address*</label><input ng-model="location" id="google_places_ac" required name="google_places_ac" type="text" class="form-control" placeholder="Address" /><p class="help-block" ng-message="required" ng-show="form.google_places_ac.$invalid">Message</p></div></div>'
},
link: function($scope, elm, attrs) {
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
$scope.location = place.name + ',' + place.geometry.location.lat() + ',' + place.geometry.location.lng() + "," + place.formatted_address;
$scope.$apply();
});
}
}
})
.has-error input {
border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<div ng-app="app">
<form name="registrationForm" ng-submit="register()" novalidate>
<div class="col-xs-12">
<google-places location=location form="registrationForm"></google-places>
</div>
</form>
</div>
I want to truncate my table cells but fit as much as possible content into them. There is an excellent solution (fiddle) which I want to implement in a directive. I need to transform a table cell from
<td>veryverylongunbreakablecontent</td>
to
<td>
<div class="container">
<div class="content">veryverylongunbreakablecontent</div>
<div class="spacer">veryverylongunbreakablecontent</div>
<span> </span>
</div>
</td>
This is a simplified example. My table cells consist of angular scope variables:
<td>{{ item.attribute.verylong }}</td>
What I have come up with so far is a directive
.directive('mwTableTruncate', function ($compile) {
return {
restrict: 'A',
templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
transclude: true,
compile: function( tElem, tAttrs ){
}
};
});
with a template
<div class="containerTest">
<div class="content">
<div ng-transclude></div>
</div>
<div class="spacer">
<div ng-transclude></div>
</div>
<span> </span>
</div>
Now I need to add soft hyphens () every 5 characters to the text in the spacer div. How can I do this?
The problem is I need to access the spacer div text after all the scope variables have been translated to add the soft hyphens.
edit#1 #sirrocco
I have examined the output from the compile, pre-link, link, post-link phase. None of these phases do translate the scope variables.
link phase
.directive('mwTableTruncate', function ($compile) {
return {
restrict: 'A',
link: function (scope, iElem, attrs) {
console.log('link => ' + iElem.html());
console.log('link text => ' + iElem.text());
}
};
});
gives me in the console:
link =>
{{ item.attributes.surname }}
link text =>
{{ item.attributes.surname }}
compile, pre-link, post-link
.directive('mwTableTruncate', function ($compile) {
return {
restrict: 'A',
templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
transclude: true,
compile: function( tElem, tAttrs ){
console.log('Compile => ' + tElem.html());
return {
pre: function(scope, iElem, iAttrs){
console.log('pre link => ' + iElem.html());
console.log('pre link text => ' + iElem.text());
},
post: function(scope, iElem, iAttrs){
console.log('post link => ' + iElem.html());
console.log('post link text => ' + iElem.text());
//debugger;
}
};
}
};
});
output in the console:
pre link => <div class="containerTest">
<div class="content">
<div ng-transclude=""></div>
</div>
<div class="spacer">
<div ng-transclude=""></div>
</div>
<span> </span>
</div>
pre link text =>
post link => <div class="containerTest">
<div class="content">
<div ng-transclude=""><span class="ng-binding ng-scope">
{{ item.attributes.surname }}
</span></div>
</div>
<div class="spacer">
<div ng-transclude=""><span class="ng-binding ng-scope">
{{ item.attributes.surname }}
</span></div>
</div>
<span> </span>
</div>
post link text =>
{{ item.attributes.surname }}
{{ item.attributes.surname }}
As you can see, none of the {{ item.attributes.surname }} variables got translated.
edit#2
Based on the hint with the timeout function in the post link phase I have come up with this solution:
directive
.directive('mwTableTruncate', function($timeout) {
return {
restrict: 'A',
templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
transclude: true,
compile: function() {
var softHyphenate = function (input) {
var newInput = '';
for (var i = 0, len = input.length; i < len; i++) {
newInput += input[i];
if (i % 5 === 0) {
newInput += '';
}
}
return newInput;
};
return {
post: function (scope, iElem) {
$timeout(function () {
var text = iElem.find('div.spacer').text().trim();
// add tooltips
iElem.find('div.content').prop('title', text);
// add soft hyphens
var textHyphenated = softHyphenate(text);
iElem.find('div.spacer').html(textHyphenated);
});
}
};
}
};
});
template
<div class="containerTest">
<div ng-transclude class="content"></div>
<div ng-transclude class="spacer"></div>
<span> </span>
</div>
How would it look like with an isolated scope sirrocco rbaghbanli?
Do not transclude. Simply set your item.attribute.verylong as ng-model for your directive. Then get the object to manipulate as you wish. In the controller add all spacers you need. Then just display the result in {{ ... }} in your template for directive.
Code:
.directive('truncateString', function ($compile) {
return {
restrict: 'E',
templateUrl: '{{ strWithBreaks }}',
scope: {
str: '=ngModel'
},
controller: ['$scope', function ($scope) {
$scope.strWithBreaks = (function (input) {
var newInput = '';
for (var i = 0, len = input.length; i < len; i++) {
newInput += input[i];
if (i % 5 === 0) {
newInput += '';
}
}
return newInput;
})(str);
}]
};
});
Usage:
<truncate-string ng-model="myVeryLongString"></truncate-string>
The directive without transclude would probably look something like:
.directive('mwTdTruncate', function() {
return {
restrict: 'A',
templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
scope:{
longText: '#mwLongText'
},
replace:true,
link: function(scope) {
var softHyphenate = function (input) {
var newInput = '';
for (var i = 0, len = input.length; i < len; i++) {
newInput += input[i];
if (i % 5 === 0) {
newInput += '';
}
}
return newInput;
};
scope.softText = softHyphenate(scope.longText);
}
};
});
and the template:
<td>
<div class="container">
<div class="content">{{longText}}</div>
<div class="spacer">{{softText}}</div>
<span> </span>
</div>
</td>
used like:
<td mw-td-truncate mw-long-text='{{yourTextVariable}}'>veryverylongunbreakablecontent</td>