jquery ui directive creating issue with angularjs ng-repeat - angularjs-directive

lostBaggageApp.directive('calendar',['$timeout', function($timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attr, ngModelCtrl) {
element.datepicker({
dateFormat: 'mm/dd/yy',
maxDate: '0',
onSelect: function (date) {
alert(date);
ngModelCtrl.$setViewValue(date);
}
});
}
There are multiple date fields on a page, and applying ng-repeat creating problem with datepicked field only. first date field is accepting value and if want to change into other date field its value is reflecting on first date field.

Related

JQuery Datatable in Angular Js Ng-Click not Working?

I have a DataTable and I am loading it using Angular Js, I have Created a directive and wrapped my DataTable in this directive, A common approach of wraping JQuery Plugin in Directive so that it can live in Angular Digest Cycle.
But the ng-click that is on button and coming from render Function of column in datatable is not clickable (Not Working, Angular did not compiled it). Is there any way to make it Clickable. I know the approach in which we use {{}} with ng-repeatto populate data in datatable. I'm looking a directive way, so you can tell me what is stoping ng-click from working or how to make my directive right! Please stick with directive approach. Code is following.
App.directive('jqtable', function () {
return {
restrict: 'E, A, C',
link: function (scope, element, attrs, controller) {
var dataTable = element.dataTable(scope.options);
scope.$watch('options.data', handleModelUpdates, true);
function handleModelUpdates(newData) {
var data = newData || null;
if (data) {
dataTable.fnClearTable();
dataTable.fnAddData(data);
}
}
},
scope: {
options: "="
}
};
});
And here is my Controller:-
$scope.options = {
aoColumnDefs: [{
"bSortable": true,
"aTargets": [ 1],
"render": function ( data, type, full, meta ) {
if(meta.col==1){
return data+" <a class='btn btn-sm btn-default' ng-click='showalert()' >Click me </a>"
}
}
}],
bJQueryUI: true,
bDestroy: true,
data:$scope.data
};
$scope.showalert=()=>
{
alert("Angular Compiled the Html");
}
Angular does not know you have injected elements to the DOM. You must $compile each row. You can do that in rowCallback. Since DataTables may inject new rows when the table is filtered, sorted or upon page change, you can add a compiled flag to prevent rows from being $compiled multiple times :
$scope.options = {
rowCallback: function(row) {
if (!row.compiled) {
$compile(angular.element(row))($scope);
row.compiled = true;
}
}
...
}
see http://next.plnkr.co/edit/KxwqSVXIogtXYx4I

Passing an object to attributes of directive in angularjs

I have a directive which creates a modal.I am trying to pass an object through attributes to this directive.
<modal-dialog model="viewSummaryDialog" info="{{info}}"></modal-dialog>
And I'm retrieving it through attributes like this
return {
restrict: 'E',
scope: {
model: '=',
info:'#',
},
link: function(scope, element, attributes) {
scope.info=scope.$eval(attributes.info);
In my HTML info is an object which has ng-model of different text fields and dropdowns
My problem is that info is not being updated with whatever I enter in the text fields.I am getting only auto selected drop down values in my info object in the directive.I understand this is because link function is being called even before I enter anything in text fields.
Is there any way to make sure that my info object is passed only after I enter all the fields in the form? I am not very clear about how to pass an object to the directive.I tried using resolve function also in my directive but that didn't work.
Thanks in advance :-)
Passing object to directive
var myApp = angular.module('myApp',[]);
myApp.directive('passObject', function() {
return {
restrict: 'E',
scope: { object: '=' },
template: '<div>Hello, {{object.prop}}!</div>'
};
});
myApp.controller('MyCtrl', function ($scope) {
$scope.object = { prop: "world" };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<pass-object object="object"></pass-object>
</div>

How to trigger ng repeat finish event again when model value changes

I have used ng-repeat finish event to trigger a function after ng-repeat finishes.
Below is the ng-repeat code
<tr ng-if="allAccounts.length > 0" ng-repeat="account in allAccounts" on-finish-render="ngRepeatFinished">
The custom directive is:
app.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
scope.$watch(scope.allAccounts, function() {
if (scope.$last === true) {
$timeout(function () {
scope.$emit(attr.onFinishRender);
});
}
});
}
}
});
and I have called my function like this in the controller:
$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
callDataTable('accountListTable');
});
It is working fine for me when first-time ng-repeat triggers but when I change model's value i.e. 'allAccounts', it doesn't call finish event again & tr doesn't reflect.
If anyone knows please provide me a working solution.
Thanks much!

angularjs directives - how to add interpolated attribute

From what I can tell, an interpolated value string expands/resolves correctly if it's specified in the template, but not if it's added later. To demonstrate, I have the following code:
describe.only('directive tests - ', function() {
it('add dynamic interpolated attribute value', function() {
module(function($compileProvider) {
$compileProvider.directive('hello', function() {
return {
restrict: 'A',
replace: true,
template: '<a foo="{{1+1}}"></a>',
compile: function link(tElement, tAttrs) {
tElement.attr('bar', '{{2+2}}'); // add an interpolated attr.
}
};
});
});
inject(function($compile, $rootScope) {
var element = angular.element('<div hello/>');
$compile(element)($rootScope);
$rootScope.$apply();
console.log(' * ', element.prop('outerHTML'));
});
});
});
and console.log prints:
<a foo="2" hello="" bar="{{2+2}}" class="ng-scope"></a>'
and NOT:
<a foo="2" hello="" bar="4" class="ng-scope"></a>'
as I'd think. What gives?
tElement.attr('bar', $interpolate('{{2+2}}')());
Right, it is too late to do this in compile, more specifically to make changes to the directive element itself that have to be compiled (it needs to be recompiled in order to make the changes work).
But the following
// replace: true,
template: '<a foo="{{1+1}}">aa</a>',
compile: function link(tElement, tAttrs) {
tElement.find('a').attr('bar', '{{2+2}}');
}
would work as expected.
Attribute watching and interpolation can also be done in link (or controller):
link: function (scope, element, attrs) {
attrs.$observe('bar', function (interpolatedBar) {
scope.bar = interpolatedBar;
});
}
It will set up a watcher on bar attribute (while $interpolate(...)() is one-time assignment and doesn't interpolate any values from scope).

HTML5: How to set focus on a text input in a list with AngularJS

I use AngularJS with the ng-repeat directive to show an array of objects as a list.
<li ng-repeat="cue in cues" class="form-inline">
<input type="text" ng-model="cues[$index].text" class="input-xlarge"/>
{{cue.isNewest}}
</li>
The property "isNewest" is true on only one element of the array. I would like to set the keyboard focus on the text input of that item. How can I do that with AngularJS?
Here is another directive implementation that uses attrs.$observe:
myApp.directive('focus', function () {
return function (scope, element, attrs) {
attrs.$observe('focus', function (newValue) {
newValue === 'true' && element[0].focus();
// or, if you don't like side effects (see #Christophe's comment):
//if(newValue === 'true') element[0].focus();
});
}
});
Note that an interpolated DOM attribute value (i.e., {{cue.isNewest}}) always evaluates to a string, hence the reason newvalue is compared to the string 'true' rather than keyword true.
HTML:
<input type="text" ng-model="cues[$index].text" focus="{{cue.isNewest}}"
class="input-xlarge" />{{cue.isNewest}}
This fiddle also has a method to toggle which item in the array should have the focus.
Note that if you do not load jQuery, we need to use element[0].focus() in the link function (not element.focus()) becaues jqLite doesn't have a focus() method.
Since you would be manipulating the DOM, you will need to create a directive. Something like:
var app = angular.module('quirli', []);
app.directive('focusable', function() {
return {
restrict: 'A',
scope: {
focusable: '#'
},
link: function(scope, elm, attrs) {
scope.$watch('focusable', function (value) {
if (value) {
elm[0].focus();
}
});
}
};
});
Html:
<html ng-app="quirli" lang="en">
....
<input type="text" ng-model="cues[$index].text" class="input-xlarge" focusable="{{cue.isNewest}}"/>
Note: untested.
There is no special feature in AngularJS to receive focus. You could solve this with a $watch in your controller, but also with a directive.
The other proposed answers work OK 9/10 times for me, but soon I was running in "$digest already in progress" fun.
I have a slightly modified version of the previous answers by asgoth and Mark Rajcok. Basically you inject the $timeout dependency and put the focus() call inside of a timeout(...). IIRC ng-focus does the same.
var app = angular.module('cgeers', []);
app.directive('focus', ["$timeout", function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(attrs.focus, function (value) {
if (value) {
$timeout(function() { element[0].focus(); });
}
});
}
};
}]);