$watch doesn't triggered in directive - angularjs

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);
}

Related

Set focus of text box in directive

I'm experimenting with an inline-edit directive form here: http://icelab.com.au/articles/levelling-up-with-angularjs-building-a-reusable-click-to-edit-directive/
I would like to know how to set the cursor in the text box that gets created when I click some text to be edited.
Here is the directive with a few minor changes to the template:
.directive("clickToEdit", function() {
var editorTemplate = '<div class="click-to-edit">' +
'<div ng-hide="view.editorEnabled" ng-click="enableEditor()">' +
'{{value}} ' +
'</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="view.editableValue" ng-blur="save()">' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
you need to add a link function like this :
link : function(scope, ele, attrs) {
scope.$watch('view.editorEnabled', function(n, o) {
if(n) ele.find('input')[0].focus();
})
}

How to call directive template on click?

I am trying to make a reusable modal dialog and I would like to load directive template on click directive itself..
function modalDialog() {
var directive = {
restrict: 'A',
link: linkFunc,
template: '<div class="modalBox--blur">' +
'<div class="modalBox">' +
'<h3>' {{title}} '</h3>' +
'<h4>' {{text}} '</h4>' +
'<button ng-click="answer(true)">Cancel</button>' +
'<button ng-click="answer(false)">Ok</button>' +
'</div>' +
'</div>',
scope: {
title: '=dialogTitle',
text: '=dialogTxt'
},
transclude: true
};
return directive;
function linkFunc($scope, element, attrs) {
element.on('click', function () {
$scope.newEl = element.parent();
$scope.newEl.append(...template Here...???);
});
}
}
This is how directive is set in the view:
<button
modal-dialog
dialog-title="modalBox.title"
dialog-txt="modalBox.subText"
type="button"
ng-click="deleteSth()"
class="button">
</button>
I can't figure out how to load template on element click :
element.on('click', function () {
$scope.newEl = element.parent();
$scope.newEl.append(template????);
});
Any tips?
Thank you in advance!
You can get the template with $templateCache
Like $templateCache.get('templateId.html')
Solution was compiling the template:
scope.modal = $compile(' <div class="modalBox--blur">' +
'<div class="modalBox">' +
'<h3>{{title}}</h3>' +
'<h4>{{text}}</h4>' +
'<button ng-click="dialogAnswer(true)">Annuleren</button>' +
'<button ng-click="dialogAnswer(false)">Ok</button>' +
'</div>' +
'</div>')(scope);
element.on('click', function () {
scope.newEl = element.parent();
scope.newEl.append(scope.modal);

Angularjs autocomplete in already created directives

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

Update ng-options hosted by a directive

I have a custom directive that displays a dropdownlist.
Is it possible to dynamically re-populate the ng-options from a datasource that comes from the controller that hosts the directive.
The datasource itself comes from a service.
Currently it works well from the initial array passed to the directive, but when I add new data (from the controller/service to this array I would like to update the item list.
Any help?
EDIT :
This is how I use my directive.
<select-item-obj-from-array datasource="ctrl.ActivityAddresses" ng-model="form.Activity.AddressID" name="AddressID" value="AddressID" label="City" .... />
My directive looks like:
app.directive('selectItemObjFromArray', function () {
return {
restrict: 'E',
replace: true,
template: function (element, attrs) {
var tpl = '';
tpl += "<div><div class=\"form-group clearfix\" >";
tpl += '<label for="' + attrs.name + '" class="col-lg-3 control-label">' + attrs.label + '</label>';
tpl += '<div class="col-lg-9">';
tpl += '<select ng-disabled="ngDisabled" name="' + attrs.name + '" ng-model="ngModel" chosen="datasource" ng-options="c.Name for c in datasource"></select>';
tpl += '</div>';
tpl += '</div>';
tpl += '</div>';
return tpl;
},
scope: {
ngModel: "=",
datasource: "="
},
link: function (scope, elem, attrs) {
var select = elem.find("select").eq(0);
select.chosen();
scope.$watch(function () {
return select[0].length;
},
function (newvalue, oldvalue) {
if (newvalue !== oldvalue) {
select.trigger("chosen:updated");
}
});
scope.$watch(attrs.ngModel, function () {
select.trigger('chosen:updated');
});
}
};
});
if my controller/service updated the ctrl.ActivityAddresses I don't know how to "reinvoke" the directive to update the dropdownlist..
You can broadcast from your service like this:
var broadcast = function() {
$rootScope.$broadcast('items.update');
};
Assuming that items is an array.
Then you can catch the broadcast in your controller or directive:
$scope.$on('items.update', function (event) {
//Do whatever you want with the items.
});
I think this is what you want? You don't need to change the ng-options directive for this.

ui-select2 inside directive bind to outer scope

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!

Resources