I'm nesting select2 input inside a directive and I want to bind the selected values to outer scope. how can I do that.
plunker example
directive code:
app.directive('optionChoices', function () {
return {
restrict: 'EA',
scope: {
type: '=',
selections: '='
},
template: '<input ng-if="type === 1" ui-select2="textChoices" ' +
'ng-model="selections" style="width:200px" />' +
'<input ng-if="type === 2" ui-select2="colorChoices" ' +
'ng-model="selections" style="width:200px" />' +
'{{\'inner:\' + selections}}',
link: function (scope, element, attrs) {
function Query(query) {
var data={
results:[]
};
if (query.term.length > 0) {
data.results.push({id:query.term,text:query.term});
}
query.callback(data);
}
scope.textChoices = {
query: Query,
tags: [],
initSelection: function () {}
};
scope.colorChoises = angular.extend({}, scope.textChoices, {
formatSelection: function(state) {
if (!state.id) return state.text;
return "<div style='background-color:yellow;'> </div>" + state.text;
}
});
}
};
});
I found the problem, and it's not that hard.
when creating isolated scope, you can not just bind to the parent scope, if doens angular will create a separate instance of the variable.
just need to bind to $parent, or to and parent object:
scope: {
option: '='
}
and in the template:
template: '<input ng-if="option.type === 1" ui-select2="textChoices" ' +
'ng-model="option.selections" style="width:200px" />' +
'<input ng-if="option.type === 2" ui-select2="colorChoices" ' +
'ng-model="option.selections" style="width:200px" />' +
'{{\'inner:\' + selections}}',
njoy!
Related
i have a directive:
function templateFn() {
return '<div class="card-wrapper">'
+ '<div class="cards-carousel">'
+ '<div class="cards-carousel-inner">'
+ '<div ng-repeat="item in cards">'
+ '<div class="item" ng-class="{\'active\': $index == $parent.ngModel.id, \'next\' : $index == $parent.ngModel.id + 1, \'prev\' : $index == $parent.ngModel.id - 1}">'
+ '<label><input id="{{item.eid}}" type="radio" ng-value="item" ng-model="$parent.ngModel">'
+ '<img alt="{{item.id}}" ng-src="{{item.url}}" /></label>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>';
}
function linkFn(scope, element, attrs) {
scope.cards = JSON.parse(attrs.cards);
scope.$watchCollection('cards', function(newValue, oldValue) {
if (newValue !== oldValue) {
scope.cards = newValue;
}
}, true);
}
return {
restrict: 'E',
required: ['ngModel'],
scope: {
ngModel: '='
},
link: linkFn,
replace: 'true',
template: templateFn
};
and in controller i make rest request to take needed cards. Cards pushed like this: ctrl.cardList.push(card)
This is my view:
<ab-card-carousel cards="{{ctrl.cardList}}"
ng-model="ctrl.debitCardItem">
</ab-card-carousel>
and in the view, when i console.log({{ctrl.cardList}}) it renders good, and as i need, but changes not made in scope.$watch function.
Can anybody help me?
Remove the interpolation from the attribute:
<ab-card-carousel ̶c̶a̶r̶d̶s̶=̶"̶{̶{̶c̶t̶r̶l̶.̶c̶a̶r̶d̶L̶i̶s̶t̶}̶}̶"̶
cards="ctrl.cardList"
ng-model="ctrl.debitCardItem">
</ab-card-carousel>
Add one-way binding:
scope: {
ngModel: '=',
cards: "<",
},
Change the linkFn to:
function linkFn(scope, element, attrs) {
̶s̶c̶o̶p̶e̶.̶c̶a̶r̶d̶s̶ ̶=̶ ̶J̶S̶O̶N̶.̶p̶a̶r̶s̶e̶(̶a̶t̶t̶r̶s̶.̶c̶a̶r̶d̶s̶)̶;̶
scope.$watchCollection('cards', function(newValue, oldValue) {
if (newValue !== oldValue) {
scope.cards = newValue;
}
}, true);
}
Hi I have created a directive for toggle button.
DIRECTIVE
app.directive('toggleBtn',[function () {
return {
restrict: 'EA',
replace: true,
require: ['name', '^ngModel'],
scope: {
isDisabled: '=',
name: '#',
ngModel: '='
},
template:
' <div class="toggle-switch on off"> ' +
' <input ng-model="ngModel" id="{{name}}" type="checkbox" ng-disabled="{{isDisabled}}" ' +
' hidden=""><label for="{{name}}" ' +
' class="ts-helper"></label> ' +
' </div> '
};
}]);
HTML
<input ng-model="sample1" name="sample1"
type="checkbox" class="someclass" ng-change="doSomething()" toggle-btn>
Directive is working fine, except ng-change. ng-change attribute is added to div, not to input-checkbox.
How to add those attributes to input-checkbox?
Not just ng-change, there can be other attributes also. Like ng-focus, title, ng-click, etc... (ng-click and title will work as it will append to main div, I'm just giving an example here).
Plunkr Demo here
Change your code to this
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.doSomething = function() {
console.log("Do something");
}
});
app.directive('toggleBtn', [function() {
return {
restrict: 'EA',
replace: true,
require: ['name', '^ngModel'],
scope: {
isDisabled: '=',
name: '#',
ngModel: '=',
ngChange: '&'
},
template: ' <div class="toggle-switch on off"> ' +
' <input ng-model="ngModel" id="{{name}}" type="checkbox" ng-change="ngChange()" ng-disabled="{{isDisabled}}" ' +
' hidden=""><label for="{{name}}" ' +
' class="ts-helper"></label> ' +
' </div> '
};
}]);
Demo
My ngMessages doesnt work inside my directives template!
I have a directive myInput with a template and a link function, inside the template function I create template string for a wrapped <label> and <input>.
Inside the Link function I use the require: '^form' FormController and retrieve the form name. Then I'm putting a ngMessages block after the wrapped elements.
(function () {
'use strict';
angular
.module('app.components')
.directive('myInput', MyInput);
/*#ngInject*/
function MyInput($compile, ValidatorService, _, LIST_OF_VALIDATORS) {
return {
require: '^form',
restrict: 'E',
controller: MyInputController,
controllerAs: 'vm',
bindToController: true,
template: TemplateFunction,
scope: {
label: '#',
id: '#',
value: '=',
validateCustom: '&'
},
link: MyInputLink
};
function MyInputController($attrs) {
var vm = this;
vm.value = '';
vm.validateClass = '';
vm.successMessage = '';
vm.errorMessage = '';
}
function TemplateFunction(tElement, tAttrs) {
return '<div class="input-field">' +
' <label id="input_{{vm.id}}_label" for="input_{{vm.id}}" >{{vm.label}}</label>' +
' <input id="input_{{vm.id}}" name="{{vm.id}}" ng-class="vm.validateClass" type="text" ng-model="vm.value" >' +
'</div>';
}
function MyInputLink(scope, element, attrs, form){
var extra = ' <div ng-messages="' + form.$name + '.' + scope.vm.id + '.$error">' +
' <div ng-messages-include="/modules/components/validationMessages.html"></div>' +
' </div>';
$(element).after(extra);
}
}
})();
Usage:
<h1>Test</h1>
<form name="myForm">
<my-input label="My Input" id="input1" value="vm.input1"></my-input>
-------
<!-- this block is hardcoded and is working, it does not come from the directive! -->
<div ng-messages="myForm.input1.$error">
<div ng-messages-include="/modules/components/validationMessages.html"></div>
</div>
</form>
Instead of adding the ngMessages block inside the link function, add it inside the compile function.
It is not as handy as in the link funciton because of the missing FormController, but it works :-)
Here the code:
compile: function(tElement, tAttrs){
var name = tElement.closest('form').attr('name'),
fullFieldName = name + '.' + tAttrs.id; // or tAttrs.name
var extra = '<div ng-messages="' + fullFieldName + '.$error">' +
' <div ng-messages-include="/modules/components/validationMessages.html"></div>' +
'</div>';
$(element).after(extra);
Here is what I did, I added to scope, myForm: '=' then in the directive's template referred to <div ng-messages="vm.myForm[vm.id].$error" >
I feel this is much cleaner than mucking around in the link function.
I already have a directive for inputbox. i need to implement Autocomplete feature on that
here is my directive code
app.directive("bhAddCategory", ["$rootScope", "$timeout",function($rootScope, $timeout) {
return {
scope: {
rmText: '=bhRmText'
},
replace: true,
template: '<div>' +
'<div class="pull-left forDrop"><input type="text" focus-on="focusMe" ng-class="myColonyList" class="effect1" placeholder="Add a colony" data-ng-model="newCategoryName" data-ng-trim="true" ng-keypress="pressEnter($event)"></div>' +
'<div class="pull-right"><img src="/images/greyplus.png" ng-class="{imageoverflow: imageOverflow}" ng-show="loadplus" data-ng-click="addCategory()" alt="add category"><img src="/images/loader.gif" ng-class="{imageoverflow: imageOverflow}" alt="" ng-show="loadgif" class="colonyloder"></div >' +
'</div>',
link: function(scope, element, attrs) {
scope.loadplus = true;
scope.pressEnter = function(keyEvent) {
if (keyEvent.which === 13)
scope.addCategory();
};
scope.resetNewCategoryName = function() {
if (scope.rmText) {
scope.newCategoryName = '';
}
};
}
};
}]);
How can i implement Auto complete here.
Any Suggestions
Thanks
i am trying to create a generic radioButton directive which will take options from controller for display:
<cs-radio-field options="gender" ng-model="genderValue"></cs-radio-field>
and the options would be like
$scope.gender = { label: "Gender", required:true, valueList: [{ text: "Male", value: "yes" },{text:"Female", value:"no"}] };
the directive is defined as:
app.directive("csRadioField", function () {
var templateHtml = function () {
return '<div ng-form="myform">' +
'<div class="control-group" class="{{options.class}}">' +
'<div class="control-label">{{options.label || "Radio"}} {{ options.required ? "*" : ""}} </div>' +
'<div class="controls">' +
'<div class="radio" ng-repeat="(key, option) in options.valueList">' +
'<label> <input type="radio" name="myfield" ng-value="option.value" ng-model="ngModel" ng-required="options.required" />{{option.text}} </label>' +
'</div>' +
'<div class="field-validation-error" data-ng-show="myform.myfield.$invalid && myform.myfield.$dirty"> ' +
'<div data-ng-show="myform.myfield.$error.required">{{options.label}} is required!!!</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
};
return {
scope: { options: '=', ngModel: '=' },
required: ['ngModel', '^form'],
restrict: 'E',
template: templateHtml,
};
});
but the ngModel is not binding in the parent scope.. mostly because of new scopes being created by ng-repeat.
how to solve this issue?
the plunker link: http://plnkr.co/edit/myS5hXwxjoDEqQI2q5Q7?p=preview
Try this in your template:
ng-model="$parent.ngModel"
DEMO
You're correct that ng-repeat creates child scopes. You're actually binding to child scopes' property.