Plunker
I'm loading data into a table using ng-repeat.
There is an onFinishRender, which emits ngRepeatFinished. However it's not being fired.
Any ideas why it's not working?
logsmgr.directive('onFinishRender', function ($timeout) {
showLog("onFinishRender");
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('ngRepeatFinished');
});
}
}
}
});
You need to add the directive to one of your repeat elements. For example, from your Plunker add on-finish-render.
<tr ng-repeat="data in model.DataList" on-finish-render>
Related
Need help with several issues. Here is simplified code:
HTML
<input type="text" title="{{e.Name}}" ng-model="e.modelName" ng-required="true" typeahead-editable="false" ng-blur="vm.isUnchanged(i)" focus-me="vm.Event"
own-typeahead typeahead-on-select="vm.changeValue($item, $model, $label, i)"
uib-typeahead="$Event, $viewValue)" typeahead-min-length="0"/>
JS
app.directive("ownTypeahead", function() {
var directive = {
link: link,
scope: true,
restrict: 'A',
require: ["ngModel"]
};
return directive;
function link(scope, element, attrs, ctrls) {
element.bind('click', function () {
if (ctrls[0].$viewValue && ctrls[0].$viewValue == ' ') {
ctrls[0].$setViewValue('');
}
ctrls[0].$setViewValue(' ');
});
element.bind('focus', function () {
if (!ctrls[0].$viewValue || ctrls[0].$viewValue == '') {
ctrls[0].$setViewValue(' ');
}
});
}
});
/**
* Directive that places focus on the element it is applied to when the
* expression it binds to evaluates to true
*/
app.directive('focusMe', ['$timeout', function focusMe($timeout) {
return function (scope, elem, attrs) {
scope.$watch(attrs.focusMe, function (newVal) {
if (newVal) {
$timeout(function () {
elem[0].focus();
}, 0, false);
}
});
};
}]);
The problems/questions are:
1) The main one. Focus after clicking on certain items triggers typeahead ddl in the input field almost always, but there are several items that move focus but don't trigger the list to be opened. Any ideas where is the issue? (the code above works in about 90% of the cases and in 100% with a click on input field)
2) Not ideal solution, but an ok workaround could be trigger a click event on the focused input field to open the list. Can't manage to get that right the angular way. How this could be done?
Got it working by adding a 200ms timeout for the focusMe:
app.directive('focusMe', ['$timeout', function focusMe($timeout) {
return function (scope, elem, attrs) {
scope.$watch(attrs.focusMe, function (newVal) {
if (newVal) {
$timeout(function () {
elem[0].focus();
}, 200, false);
}
});
};
}]);
If anyone has better suggestions would accept the answer.
I am using Angular Bootstrap Selectpicker.
I am using angular version 1.4.7.
For select picker they provide directive,
angular.module('angular-bootstrap-select', [])
.directive('selectpicker', ['$parse', function ($parse) {
return {
restrict: 'A',
require: '?ngModel',
priority: 10,
compile: function (tElement, tAttrs, transclude) {
tElement.selectpicker($parse(tAttrs.selectpicker)());
tElement.selectpicker('refresh');
return function (scope, element, attrs, ngModel) {
if (!ngModel) return;
scope.$watch(attrs.ngModel, function (newVal, oldVal) {
scope.$evalAsync(function () {
if (!attrs.ngOptions || /track by/.test(attrs.ngOptions)) element.val(newVal);
element.selectpicker('refresh');
});
});
ngModel.$render = function () {
scope.$evalAsync(function () {
element.selectpicker('refresh');
});
}
};
}
};
}]);
Select picker looks like
<select class="form-control" data-style="btn-default"
data-live-search="true" selectpicker multiple
data-selected-text-format="count>2"
data-collection-name="users"
ng-model="selectedUsers"
ng-options="user.name for user in users">
</select>
Above case, selectedUser will have tickmarks and If I change value for selectedUsers from controller. It not show tick marks for updated selectedUsers options.
When I select multiple options it shows tick mark for selected options.
Then if I refresh view then though ng-model have previous values still it don't show tick mark for values in ng-model.
Plunker
I simplified your code to work. Check this Demo
.directive('selectpicker', ['$parse', selectpickerDirective]);
function selectpickerDirective($parse) {
return {
restrict: 'A',
priority: 1000,
link: function (scope, element, attrs) {
//New change
scope.$watch(attrs.ngModel, function(n, o){
element.selectpicker('val', $parse(n)());
element.selectpicker('refresh');
});
}
};
}
EDIT 1
Look this: http://plnkr.co/edit/4TiSJwKtcln9z39cxHZ3?p=preview
The library bootstrap-select is compatible with jquery, but not compatible with angular. For this you can got it utilizing advanced artifice of programmer. rsrsrs. Look in my example. I simulate click of user in element.
angular.element("li[data-original-index='1']").find("a").click();
EDIT 2
Change selectpickerDirective to:
function selectpickerDirective($parse) {
return {
restrict: 'A',
priority: 1000,
link: function (scope, element, attrs) {
scope.$watch(attrs.ngModel, function(n, o){
if(n)
element.selectpicker('val', ["string:" + n[0].name]);
element.selectpicker('refresh');
});
}
};
}
is it possible to get the clicked row (scope) of a element in ng-repeat without nowing the name?
For example: scope.person works, but when I change persons into another name I can't use my directive global.
I need the data to do a edit like this: http://vitalets.github.io/x-editable/
I will write a directive which changes the text into a input field. To save it I need the name of the field, "lastname" in the example and the ID from the row.
HTML:
<tr ng-repeat="person in persons | orderBy:lastname">
<td class="editable">{{person.lastname}}</td>
<td>{{person.surname}}</td>
</tr>
Directive:
app.directive('editable', [function () {
return {
restrict: 'C',
link: function (scope, elem, attrs) {
elem.bind('click', function(event) {
console.log(scope.person)
});
}
};
}])
You can use Angular's tracking ng-repeats by $index and pass it to your directive:
HTML:
<tr ng-repeat="person in persons | orderBy:lastname">
<td editable="$index" class="editable">{{person.lastname}}</td>
<td>{{person.surname}}</td>
</tr>
Directive:
app.directive('editable', [function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('click', function(event) {
console.log(attrs.Editable);
});
}
};
}])
You are already catching the current scope and it is working fine you just need to manipulate the data and apply scope.$apply();
app.directive('editable', [function () {
return {
restrict: 'C',
link: function (scope, elem, attrs) {
elem.bind('click', function(event) {
console.log(scope.person)
scope.person.surname="hello"
console.log(scope.person)
scope.$apply();
});
}
};
}])
In the first console output you can see the original clicked element and in second console you can see the maupilated data.
Now why apply is required:- It is required to run the digest cycle of angular to adapt the change happen outside the scope of angular js (bind is jquery event not angular's).
Plunker
Add a Scope to your directive so you can pass any Model to be edited.
And display the ID with the Attrs variable.
app.directive('editable', [function () {
return {
scope: {
model : '='
},
restrict: 'C',
link: function (scope, elem, attrs) {
elem.bind('click', function(event) {
alert(scope.model +" "+ attrs.id )
});
}
};}]);
the html:
<span class="editable" model="person.lastname" id="{{$index}}">{{person.lastname}}</span>
The Fiddle
Browse how works the custom directives in angular. You can pass like parameter the lastname through 'attrs' in your link. Something like this:
html code:
<my-first-directive lastname="{{person.lastname}}"></my-first-directive>
custom directive code:
link: function (scope, elem, attrs) {
elem.bind('click', function(event) {
console.log(attrs['lastname'])
});
}
This approach not is good in my opinion. But i hope it works you.
If you read about scopes in directives you will can try other approachs.
You can pass the same parameter to directive scope so.
In your directive:
return {
restrict: 'C',
scope: {
lastname: '=' // If you want know more about this, read about scopes in directives
}
link: function (scope, elem, attrs) {
elem.bind('click', function(event) {
console.log(scope.lastname) // now, scope.lastname is in your directive scope
});
}
};
Be careful whit names when you work with directives. If your variable is 'myVar', when you write the directive html code you need write:
<my-first-directive my-var="myVar"></my-first-directive>
For the same reason that you need write 'my-first-directive' when you name directive is 'myFirstDirective'.
Good luck!
I have created a directive, ngAfterRender, that I am trying to use to wire up fancybox:
Template
<div ng-after-render="wireUpFancyBox($event)" ng-bind-html="Content"></div>
Directive
.directive('ngAfterRender', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
$timeout(function () {
scope.$eval(attrs.ngAfterRender, { $element: element });
});
}
};
}]);
Controller
$scope.wireUpFancyBox = function ($element) {
$element.find('a').fancybox($.extend(true, {}, fancyboxOptions, {
scrolling: 'auto',
type: 'inline'
}));
};
Unfortunately, the wireUpFancyBox() method is not called when the HTML Content binding changes.
What can I do here?
If you want wireUpFancyBox called every time the ng-bind changes then you want something like this
myApp.directive('ngAfterRender', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(function () {
return scope.$eval(attrs.ngBindHtml);
},
function (value) {
$timeout(function () {
scope.$eval(attrs.ngAfterRender, { $element: element });
});
});
}
};
}]);
Here we put a watch on the evaluated ng-bind-html expression and then fire off your eval on a change.
fiddle
It seems everyone is asleep on the angularjs google group :)
Here's my problem:
I have a select in a directive, and I want to bind a function to the 'change' event of that select.
My problem is that when I use this directive in an ng-repeat loop, the bind to the event doesn't work anymore (why ??).
EDIT:
In my real case, there are three or more <select>, created and populated with data from a json file.
Here is a simplified version of the directive, and I made a plunker as well.
angular.module('test', [])
.directive('mySelect', function() {
var baseElt = angular.element('<select><option>1</option><option>2</option></select>');
return {
restrict: 'E',
compile: function(topElement) {
var elt = baseElt.clone();
topElement.append(elt);
return function(scope, element, attributes, ngModelCtrl) {
elt.bind('change', function() {
alert("change !");
});
};
}
};
});
you need
app.directive('mySelect', function() {
return {
restrict : 'E',
template : '<select><option>1</option><option>2</option></select>',
link : function(scope, element, attributes, ngModelCtrl) {
element.bind('change', function() {
console.log("change !");
});
}
}
});
Demo: Fiddle