ng-switch to change user interface of a directive - angularjs

I've created a directive for showing a person details:
angular.module('person.directives', []).
directive("person", function() {
return {
restrict: "E",
templateUrl: "person/views/person.html",
replace: true,
scope: {
myPerson: '='
},
link: function (scope, element, attrs) {
}
}
});
the view:
<div>
<span>FirstName: {{myPerson.firstName}}</span><span>LastName: {{myPerson.lastName}} </span>
</div>
The way it's called:
<person my-person="mandat.Person"></person>
mandat being a property of the parent controller.
Now, if myPerson is null, the UI for the directive should show a search button instead of the person details.
What's the best way for doig that ? Can I use the ng-switch statement ? How would I use it in this particular case ?

I found out... I use ng-show and ng-hide
<div>
<div ng-show="myPerson">
<span>FirstName: {{myPerson.firstName}}</span><span>LastName: {{myPerson.lastName}}</span>
</div>
<div ng-hide="myPerson">
<button>search</button>
</div>

Related

AngularJS model update but view not updating [duplicate]

I need to modify a root scope attribute from within a callback inside a directive. But the directive is in a inner scope created by a switch directive.
HTML
<div ng-app="app" ng-controller='AppController'>
<p>Selected: {{ selected }}</p>
<div ng-switch on="selected">
<div ng-switch-default>
<p>Item: {{ selected }}</p>
<custom-tag selected-item="selected" />
</div>
<div ng-switch-when="New value">
<p>Worked</p>
</div>
</div>
</div>
JavaScript
angular.module('app', [])
.directive("customTag", [function () {
return {
restrict: "E",
replace: true,
template: "<input type='button' value='Click me' />",
link: function (scope, element, attrs) {
element.bind('click', function () {
scope[attrs.selectedItem] = "New value";
scope.$apply();
});
}
};
}]);
function AppController($scope) {
$scope.selected = 'Old value';
}
Fiddle: http://jsfiddle.net/nJ7FQ/
My objective is to be able to display "New value" in the Selected area.
How can I accomplish what I am trying to do? What am I doing wrong?
Besides, as I am trying to make a component. Is there a way to do the same but with an isolated scope?
I updated the fiddle, basically had to go to the parent to get the right "selected" variable, also used the isolate scope = to get two way binding between the value passed in and the internal model.
http://jsfiddle.net/nJ7FQ/2/
angular.module('app', [])
.directive("customTag", [function () {
return {
restrict: "E",
replace: true,
template: "<input type='button' value='Click me' />",
scope: {model:'='},
link: function (scope, element, attrs) {
element.bind('click', function () {
scope.model[attrs.selectedItem] = "New value";
scope.$apply();
});
}
};
}]);
function AppController($scope) {
$scope.selected = 'Old value';
}
and the HTML
<div ng-app="app" ng-controller='AppController'>
<p>Selected: {{ selected }}</p>
<div ng-switch on="selected">
<div ng-switch-default>
<p>Item: {{ selected }}</p>
<custom-tag selected-item="selected" model="$parent" />
</div>
<div ng-switch-when="New value">
<p>Worked</p>
</div>
</div>
</div>
Updated the fiddle to use your original reading of the property from the attribute:
http://jsfiddle.net/nJ7FQ/4/
I improved the jsfiddle a bit:
angular.module('app', [])
.directive("customTag", ['$parse', function ($parse) {
return {
restrict: "E",
replace: true,
template: "<input type='button' value='Click me' />",
link: function (scope, element, attrs) {
element.bind('click', function () {
scope.$apply(function () {
$parse(attrs.selectedItem).assign(scope.$parent, "New value");
});
});
}
};
}]);
function AppController($scope) {
$scope.selected = { 'foo': 'Old value' };
}
http://jsfiddle.net/nJ7FQ/15/
This way, the scope value, you want to change can also be an object property like selected.foo in the example. Also, I removed the scope parameter and told the directive to always use the parent scope. And finally I wrapped the click handler into the $apply callback (see here for example). Better would be, of course, to use ngClick instead of the element.bind().

Angular directive which isn't present in the DOM

I would like to have a directive that I can use for grouping ng-if or ng-switch-when like:
<empty ng-switch-when="expression">
... Lots of little DOM nodes ...
</empty>
If I just do
.directive('empty', function() {
return {
restrict: 'E',
};
})
then it works, but still has an <empty> in the DOM, to which CSS selectors are applying (particularly problematic are the direct child selectors). So can I get it out of the DOM completely?
For example: http://plnkr.co/edit/FBFHS7A66he73xA2wlNy?p=preview should have a red link.
Try this:
app.directive('empty', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
link: function (scope, element, attrs, ctrl, transclude) {
transclude(scope, function (content) {
element.replaceWith(content);
});
}
};
})
Or you can likewise use scope.$parent (depending on which scope you need), e.g.
transclude(scope.$parent, function (content) {
Working plunker here.
Try this
app.directive('empty', function() {
return {
restrict: 'E',
link: function (scope, element, attrs) {
element.replaceWith($compile(element.contents())(scope));
}
};
})
Demo http://plnkr.co/edit/2cbpiWOIW5EUuuDjkbB5?p=preview
How about this:
app.directive('empty', function ($compile) {
return {
restrict: 'E',
link: function (scope, element, attrs) {
var content = $compile(element.html())(scope);
element.parent().prepend(content);
element.remove();
}
};
})
http://plnkr.co/edit/ttqO91Dcr4Y9INuyJUlO?p=preview
Note: if you want to make sure the element is exactly at the same place, you can use jQuery's insertBefore instead of parent().prepend
For ng-if you can use ng-if-start and ng-if-end, much like ng-repeat-start and ng-repeat-end:
<p ng-if-start="true">First visible paragraph</p>
<p>Another visible paragraph</p>
<p ng-if-end>Last visible paragraph</p>
<p ng-if-start="false">First hidden paragraph</p>
<p>Another hidden paragraph</p>
<p ng-if-end>Last hidden paragraph</p>
which can be seen working at http://plnkr.co/edit/c7C0WDx93rMSo3i9Taro?p=preview
For ng-switch you can use ng-switch-when-start and ng-switch-when-end:
<div ng-switch on="selection">
<div ng-switch-when-start="a">A 1</div>
<div>A 2</div>
<div ng-switch-when-end>A 3</div>
<div ng-switch-when-start="b">B 1</div>
<div>B 2</div>
<div ng-switch-when-end>B 3</div>
</div>
which can be seen working at http://plnkr.co/edit/cRjHcmjODBzwm1BjeSuO?p=preview
To achieve this, I suspect ngIf and ngSwitchWhen must use the multiElement option when they're defined.
Is there some reason that you cant make it a comment directive?
As in restrict: 'M'
and then:
<!-- directive: empty -->
https://code.angularjs.org/1.3.16/docs/guide/directive
scroll down to directive types for more info

AngularJs transclude not working in Directive template or templateURL

I have written a custom directive like so, notice I have commented out the template URL that contains the same HTML structure and the template property:
.directive('sillyDirective', function ( ) {
'use strict';
return {
restrict: 'A',
replace: false,
transclude: true,
template: '<h2>Welcome to my site</h2>',
//templateUrl: '/views/hello.html' ,
link: function (scope, element, attrs) {
element.bind('click', function (){
alert('you click me! I am clicked');
});
};
});
In my HTML view I have the following...
<div data-silly-directive>
<div><img src="logo.jpg></div>
<div><h1>My First Website</h1></div>
</div>
The problem is the content of the directive, e.g.:
<div><img src="logo.jpg></div>
<div><h1>My First Website</h1></div>
is being overwritten with the template content even thought I have set transclude to true and replace to false? What am I doing wrong here?
you need to specify ng-transclude in the template of your directive, this will let angular know where to insert the content of the markup.
app.directive("foo", function() {
return {
transclude: true,
template: "<div>the template</div><div ng-transclude></div>"
};
})
html:
<div foo>
Some Content Here
</div>
result:
<div foo>
<div>the template</div>
<div ng-transclude>Some Content Here</div>
</div>
here's a plnkr
source: https://www.accelebrate.com/blog/angularjs-transclusion-part-1/
Your template must contain an element with an ng-transclude attribute. That's where the body will be "pasted" by angular.
See
https://docs.angularjs.org/api/ng/directive/ngTransclude

Angularjs Directive finding element inside ngIf

I have created a angularjs directive that are supposed to display an address.
$(elem).find('button').length
now return the correct value but it have been called a hack and is there a better way to do it. I understand that ngIf creates a child scope and the button element isn't available when my link code runs if I don't wrap it in $timeout.
So what is the pretty way to access the element inside my ngIf without the $timeout hack?
My Directive
angular.module('directives')
.directive('addresss', ['$timeout', function ($timeout) {
return {
restrict: 'AE',
scope: {
address: '='
},
templateUrl: 'template........ ',
link: function(scope,elem,attr){
$timeout(function(){
console.log($(elem).find('button').length);
})
}
};
}]);
Template for address directive
<div class="spacer">
<h1>Address</h1>
<div>
<strong>{{address.name}}</strong>
</div>
<div ng-if="address.name">
<button class="btn-link">Delete</button>
</div>
</div>
if all you want to bind a click event you could just put a ng-click in the button:
JS:
app.directive('address', [function () {
return {
restrict: 'AE',
scope: {
address: '='
},
templateUrl: 'template.html ',
link: function(scope,elem,attr){
scope.myClickHandler = function() {
console.log('button clicked');
});
}
};
Template:
<div class="spacer">
<h1>Address</h1>
<div>
<strong>{{address.name}}</strong>
</div>
<div ng-if="address.name">
<button ng-click="myClickHandler()" class="btn-link">Delete</button>
</div>
</div>
Try this (if I get well your question)
html
<div data-ng-controller="MainController">
<div data-my-dir address="address"></div>
</div>
js
angular.module('myApp', [])
.controller('MainController',function($scope) {
$scope.address = {
name : 'myname'
};
})
.directive("myDir", function () {
return {
scope:{
address: '=',
},
template:'<button class="btn-link" ng-if="address.name">Delete</button>',
link: function (scope, elem) {
console.log(scope.address.name);
}
}
});

Bootstrap switch not working for nested directives inside ng-repeat

Please read the code below:
<div ng-repeat="item in data.items">
<list-item></list-item>
</div>
Html(list_item.html) of the above directive(listItem) is as below(have shown only a small part of html):
<div class="active-icon-list">
<switch-check status="{{ item.status }}"></switch-check>
</div>
js of the above directive is as below:
directives.directive('cusListItem', function(){
return {
replace: true,
restrict: 'E',
templateUrl: "list_item.html",
link: function($scope, iElm, iAttrs, controller) {
// -----
}
};
});
Html(switch_check.html) of the above directive(switchCheck) is as below:
<div class="make-switch switch-small switch-mini active-list-switch">
<input type="checkbox" checked ng-if="status == 'active'">
<input type="checkbox" ng-if="status == 'inactive'">
</div>
js of the above directive is as below:
directives.directive('switchCheck', function($timeout) {
var switches = [];
return {
replace: true,
restrict: 'E',
scope: { status: '#'},
templateUrl: "switch_check.html",
link: function postLink($scope, iElm, iAttrs) {
iElm['bootstrapSwitch']();
}
}
});
I have made directives for the purpose of reusability.
Since I am using bootstrapSwitch.js instead of normal checkbox, I have created a directive.
If a remove ng-if and write a traditional input tag, this works properly.
<input type="checkbox" checked>
But if I use ng-if, iElm['bootstrapSwitch'](); fails and checkbox does not appear at all.
Is there a way(an efficient one) to figure out a solution for this one?
Please tell me if my question is not clear.

Resources