AngularJS - How to show custom directives based on condition - angularjs

I have to show a custom directive (i.e. task-moveable) based on some condition. I have to only show the task-movable attribute for tasks which is not completed yet. Is there any way we can do this in Angularjs?
HTML Code:
<div class="gantt-body-background" ng-repeat="row in gantt.rows" task-moveable>
....
</div>
Thanks in advance.

You could make a tweak such that your taskMoveable directive can observe a value assigned to it. From there do an $eval on the value of the taskMoveable attribute to get your boolean.
As an example:
app.directive('taskMoveable', function () {
return {
controller: function ($scope, $element, $attrs) {
$scope.taskMoveable = {};
$attrs.$observe('taskMoveable', function (value) {
if (value) {
$scope.taskMoveable.amIMoveable = $scope.$eval(value);
}
});
},
template: '<span ng-bind="taskMoveable.amIMoveable"></span>'
};
});
See my plunk here for a more detailed example:
http://plnkr.co/edit/0nK4K9j3SmNnz8PgRYfR

You could use ng-if for that whole element. Something like this.
<div class="gantt-body-background" ng-repeat="row in gantt.rows" ng-if="thing.stuff" task-moveable>
....
</div>
Then that div would only be in the DOM if thing.stuff was truthy.

Related

Execute script/function on each iteration of ng-repeat

I am using ng-repeat on an element like this:
<div ng-repeat="aSize in BC.aOutputSizesArr" style="width:{{aSize}}px; height:{{aSize}}px;">
{{aSize}}
<canvas/>
<script>alert({{aSize}})</script>
</div>
So basically on every repeat, i need to draw to the canvas based on the value of aSize, is it possible to execute a function on every iteration of ng-repeat? I tried putting that script tag in there, but it doesnt work.
Here's an example of what I mean with using a directive.
This directive:
angular.module('directives', []).directive('alerter', function () {
return {
model: {
size: '#'
},
link: function ($scope, element, attrs, controller) {
alert(attrs.size)
}
};
});
Used like:
<alerter size=10>alert 10</alerter>
<alerter size=15>alert 15</alerter>
Will execute.
You can use a custom directive or the directive ngInit
and pass a function from the controller.
This directive will execute once the tag is created by the ngRepeat.
<canva ng-init="function()"/> <!-- function from $scope -->
As #Jorg said, create a directive:
.directive('myCanvas', function(){
return {
scope: {
size: '=size'
},
template: '<canvas></canvas>',
link: function(scope, elem, attrs){
alert(scope.size);
}
};
});
Then inside your ng-repeat
<div ng-repeat="aSize in BC.aOutputSizesArr">
{{aSize}}
<my-canvas size="aSize"/>
</div>
This was quickly written and untested, but hopefully you get the idea. Just remember that the example above is just one way of binding, depending on your requirements for aSize (like can it be changed dynamically, etc).
<tr ng-repeat="app in appList" ng-init="getActivationFunction(app)"> <!-- function from $scope -->
<td><h4> {{ app.Name }} </h4></td>
<td> <img src="{{ app.ava_img }}"/> </td>
</tr>
in controller call the below function ...
$scope.getActivationFunction = function(modelRecieve) {
Service.getServiceDate(modelRecieve.name)
.then(function(response) {
var date = response.data.image;
$scope.app.ava_img = date;
},
// ...
};

Angular ng-init pass element to scope

Is there a way to get the current element where my ng-init is currently binded on?
For example:
<div ng-init="doSomething($element)"></div>
I believe that there is a way for ng-click but I can't do this using ng-init like this:
<div ng-click="doSomething($event)"></div>
Controller:
$scope.doSomething = function(e){
var element = angular.element(e.srcElement);
}
How do I do this with ng-init?
Your HTML:
<div ng-app='app' ng-controller="Ctrl">
<div my-dir></div>
</div>
Your Javascript:
var app = angular.module('app', [], function () {});
app.controller('Ctrl', function ($scope) {
$scope.doSomething = function (e) {
alert(e);
};
});
app.directive('myDir', function () {
return function (scope, element, attrs) {
scope.doSomething(element);
};
});
From above, element will be your DOM object.
Don't do it.
As #CodeHater said, handling DOM manipulation in a directive is a better solution than engaging controller with the element.
I was also looking for similar thing but finally I created one more directive added to the child div element. In the directive code block I get the element object and placed all my event related function and other instructions over there. Also, I add the element to $scope object, this help me to use this object else where as well and no need to find it every time I need it.

Changing src of only hovered ng-include element, where value of src is a $scope variable

I have multiple ng-include elements that have src attribute set to $scope.template_url.
I want to change src of hovered element only to new template but changing it's value will change all of elements. How can i implement it?
Html code:
<section class="parent">
<div data-ng-include data-src="template_url"></div>
</section>
Javascript (in controller):
angular.element(document).on('mouseover', '.parent', function(){
$scope.$apply(function () {
$scope.template_url = "path/to/new/template.html";
});
});
Writing jQuery dom manipulation is dirty and also don't works:
$(this).attr('data-src', "path/to/new/template.html");
I'd suggest making this a directive. Directives have their own scope, so you can still do the "on hover use a different template" idea, but for each individual one that is hovered.
<div>
<div data-some-directive=""></div>
</div>
var myApp = angular.module('myApp',[]);
myApp.directive('someDirective', function() {
return {
controller: function ($scope) {
$scope.model = "Hello"
$scope.mouseover = function () {
$scope.model = "Hovered!";
};
},
scope:{},
restrict: 'AE',
replace: true,
template: '<div><input ng-mouseover="mouseover()" ng-model="model"></div>',
};
});
Heres a fiddle to see it in action.
Tweak the template variable in the directive to use a variable on your model for the include url.
By the way, angular already has a mouseover handler, so i've just linked that into the controller with ng-mouseover in the template.

Ng-controller on same element as ng-repeat - no two-way-data-binding

I can't get two-way-data-binding to work in an Angular js ng-repeat.
I have an ng-controller specified on the same element that has the ng-repeat specified -
I just learnt that by doing this, I can get a hold of each item that is being iterated over by ng-repeat. Here is the HTML:
<div ng-controller="OtherController">
<div id="hoverMe" ng-controller="ItemController" ng-mouseenter="addCaption()"
ng-mouseleave="saveCaption()" ng-repeat="image in images">
<div class="imgMarker" style="{{image.css}}">
<div ng-show="image.captionExists" class="carousel-caption">
<p class="lead" contenteditable="true">{{image.caption}}</p>
</div>
</div>
</div>
</div>
And here is the ItemController:
function ItemController($scope){
$scope.addCaption = function(){
if($scope.image.captionExists === false){
$scope.image.captionExists = true;
}
}
$scope.saveCaption = function(){
console.log($scope.image.caption);
}
}
And the OtherController:
function OtherController($scope){
$scope.images = ..
}
When I hover the mouse over the #hoverMe-div - the caption-div is added correctly. But when I input some text in the paragraph and then move the mouse away from the #hoveMe-div, the $scope.image-variables caption value is not updated in the saveCaption-method. I understand I'm missing something. But what is it?
You don't need a ng-controller specified on the same element that has the ng-repeat to be able to get each item.
You can get the item like this:
<div ng-repeat="image in images" ng-mouseenter="addCaption(image)" ng-mouseleave="saveCaption(image)" class="image">
And in your controller code:
$scope.addCaption = function (image) {
if(!image.captionExists){
image.captionExists = true;
}
};
To get contenteditable to work you need to use ng-model and a directive that updates the model correctly.
Here is a simple example based on the documentation:
app.directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, controller) {
element.on('blur', function() {
scope.$apply(function() {
controller.$setViewValue(element.html());
});
});
controller.$render = function(value) {
element.html(value);
};
}
};
});
Note that the directive probably needs more logic to be able to handle for example line breaks.
Here is a working Plunker: http://plnkr.co/edit/0L3NKS?p=preview
I assume you are editing the content in p contenteditable and are expecting that the model image.caption is update. To make it work you need to setup 2 way binding.
2 way binding is available for element that support ng-model or else data needs to be synced manually. Check the ngModelController documentation and the sample available there. It should serve your purpose.

AngularJS input with focus kills ng-repeat filter of list

Obviously this is caused by me being new to AngularJS, but I don't know what is the problem.
Basically, I have a list of items and an input control for filtering the list that is located in a pop out side drawer.
That works perfectly until I added a directive to set focus to that input control when it becomes visible. Then the focus works, but the filter stops working. No errors. Removing focus="{{open}}" from the markup makes the filter work.
The focus method was taken from this StackOverflow post:
How to set focus on input field?
Here is the code...
/* impersonate.html */
<section class="impersonate">
<div header></div>
<ul>
<li ng-repeat="item in items | filter:search">{{item.name}}</li>
</ul>
<div class="handle handle-right icon-search" tap="toggle()"></div>
<div class="drawer drawer-right"
ng-class="{expanded: open, collapsed: !open}">
Search<br />
<input class="SearchBox" ng-model="search.name"
focus="{{open}}" type="text">
</div>
</section>
// impersonateController.js
angular
.module('sales')
.controller(
'ImpersonateController',
[
'$scope',
function($scope) {
$scope.open = false;
$scope.toggle = function () {
$scope.open = !$scope.open;
}
}]
);
// app.js
angular
.module('myApp')
.directive('focus', function($timeout) {
return {
scope: { trigger: '#focus' },
link: function(scope, element) {
scope.$watch('trigger', function(value) {
if(value === "true") {
console.log('trigger',value);
$timeout(function() {
element[0].focus();
});
}
});
}
};
})
Any assistance would be greatly appreciated!
Thanks!
Thad
The focus directive uses an isolated scope.
scope: { trigger: '#focus' },
So, by adding the directive to the input-tag, ng-model="search.name" no longer points to ImpersonateController but to this new isolated scope.
Instead try:
ng-model="$parent.search.name"
demo: http://jsbin.com/ogexem/3/
P.s.: next time, please try to post copyable code. I had to make quite a lot of assumptions of how all this should be wired up.

Resources