ng-else directive in angularjs - javascript

how can we create ngELSE directive as same as ngIF directive?
below code for ngIfDirective. Shall we customize the code for ngELSE?
var ngIfDirective = ['$animate', function($animate) {
return {
multiElement: true,
transclude: 'element',
priority: 600,
terminal: true,
restrict: 'A',
$$tlb: true,
link: function($scope, $element, $attr, ctrl, $transclude) {
var block, childScope, previousElements;
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
if (value) {
if (!childScope) {
$transclude(function(clone, newScope) {
childScope = newScope;
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
// Note: We only need the first/last node of the cloned nodes.
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
// by a directive with templateUrl when its template arrives.
block = {
clone: clone
};
$animate.enter(clone, $element.parent(), $element);
});
}
} else {
if (previousElements) {
previousElements.remove();
previousElements = null;
}
if (childScope) {
childScope.$destroy();
childScope = null;
}
if (block) {
previousElements = getBlockNodes(block.clone);
$animate.leave(previousElements).then(function() {
previousElements = null;
});
block = null;
}
}
});
}
};
}];

Normally we use like this
normal if-else
if(video == video.large){
<!-- code to render a large video block-->
}
else{
<!-- code to render the regular video block -->
}
AngularJS ng-if
<div ng-if="video == video.large">
<!-- code to render a large video block-->
</div>
<div ng-if="video != video.large">
<!-- code to render the regular video block -->
</div>
But if you are too specific that you want a directive like ng-if, ng-else-if, and ng-else then use ng-elif
Working Demo
<div ng-if="someCondition">
...
</div>
<p>
Some random junk in the middle.
</p>
<div ng-else-if="someOther && condition">
...
</div>
<div ng-else-if="moreConditions">
...
</div>
<div ng-else>
...
</div>

En else statement wouldn't make much sense on its own.
You can mimick an else statement in 2 ways with vanilla AngularJS
1. Simply use the negated check in a second ng-if
<div ng-if='myConditionIsTrue'></div>
<div ng-if='!myConditionIsTrue'></div>
2. use the ngSwitch directive
<div ng-switch="myCondition">
<div ng-switch-when="true"></div>
<div ng-switch-default></div>
</div>

Do this, its the reverse of ng-if. Simply saying ! (NOT) Value has the same effect as ng-else would. There are ng-else-if (called ng-elif) directives as well, if that's more what you're looking for.
<div ng-controller="myCtrl as ctrl">
<div ng-if="ctrl.isTrue">If</div>
<div ng-if="!ctrl.isTrue">If</div>
</div>
Though there is literally no point to creating an ng-else directive when you can simply negate the checked value in ng-if, you can modify the ng-if directive like so to achieve the exact same thing
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
if (!value) { // add the ! here instead and name this new directive ngElse

In this it has explained how you could use the ng-else through ng-elif
Example:
<div ng-if="someTest" ng-then="theTestPassed">
Some things that assume that "someTest" is true.
</div>
<div ng-else="theTestPassed">
Some other things that assume that "someTest" is false.
</div>
http://zachsnow.com/#!/blog/2014/angularjs-ng-elif/
Also see this: http://plnkr.co/edit/XSPP3jZL8eehu9G750ME?p=preview

Related

AngularJS - ng-show not displaying item

So I have this inside my controller:
var myApp = angular.module('app', [], function ($interpolateProvider) {
$interpolateProvider.startSymbol('[%');
$interpolateProvider.endSymbol('%]');
});
myApp.controller('MyController', function ($scope) {
$scope.show = [];
// confirmed this returns true when intended
$scope.showElement = function (id) {
return ($scope.show.indexOf(id) > -1);
};
});
And my HTML structured as below, with my-class using display: none; and other rules which are imperative to the display of this element. Because of the number of instances where it is being used I cannot simply remove the class or alter its rules. In all other instances in the application, this works as expected.
<div class="my-class" ng-show="showElement(obj.id)">
...
</div>
The element is not shown on page load, nor is its appearance updated if the underlying variable $scope.show is changed.
The previous development team was manually (by using deep and obfuscated Javascript) adding an additional CSS class in the other instances where it was being used.
My solution was to add a visible class using the ng-class directive:
<div class="my-class" ng-class="{'visible': showElement(obj.id)}">
....
</div>

Template content not updating on consecutive calls Angular

Very new to Angular and after searching all over the show I simply cannot find a solution to my problem.
I have the following function in a directive/controller:
ModalIssueController.prototype.openModal = function (e, issue) {
this._dataService.getMain().then(function (model) {
this._$scope.modalIssue.open = true;
this._$scope.modalIssue.issue = model.getIssueById(issue);
this._windowService.setModalOpen(true);
}.bind(this));
};
The above function is called each time the user clicks on a different issue from a list. This opens a modal and shows the content related to issue.
When the modal is closed via a close button, the following is called:
ModalIssueController.prototype.closeModal = function () {
this._$scope.modalIssue.open = false;
this._windowService.setModalOpen(false);
this._$timeout(function () {
this._$location.url('/');
}.bind(this));
};
The problem is, even though I can see that the value of this._$scope.modalIssue.issue changes to reflect the new issue that was clicked, the content in the modal never changes, but instead, continues to show the data from the first selected issue ;(
Am I missing something here? Is there an additional step I need to add to ensure that the data in the template is updated?
Here is the directive 'set-up':
var ModalIssueDirective = function () {
return {
restrict: 'A',
replace: true,
scope: true,
controller: ModalIssueController,
templateUrl: '/app/lorax/directives/modal-issue.tpl.html'
};
};
And here is the template I am populating:
<section class="modal modal--fade-show modal--issue" ng-show="modalIssue.open" >
Close
<h1 class="detail-header-title">{{::modalIssue.issue.getTitle()}}</h1>
<div class="detail-main__copy">{{::modalIssue.issue.getNarrative()}}</div>
<header class="detail-link__header">
<h1>{{::modalIssue.issue.getMiscLocale().mozDoingLabel}}</h1>
</header>
<p class="detail-link__copy">{{::modalIssue.issue.getMozActionCopy()}}</p>
<a ng-if="::modalIssue.issue.getMozActionLink().length === 1" href="{{::modalIssue.issue.getMozActionLink()[0].url}}" class="btn detail-link__btn">{{::modalIssue.issue.getMozActionLink()[0].copy}}</a>
<a ng-if="::modalIssue.issue.getMozActionLink().length > 1" ng-repeat="link in ::modalIssue.issue.getMozActionLink()" href="{{link.url}}" class="detail-link__multiple">{{link.copy}}<span class="icon-arrow-right"></span></a>
<header class="detail-link__header">
<h1>{{::modalIssue.issue.getMiscLocale().yourDoingLabel}}</h1>
</header>
<p class="detail-link__copy">{{::modalIssue.issue.getYourActionCopy()}}</p>
<a ng-if="::modalIssue.issue.getYourActionLink().length === 1" href="{{::modalIssue.issue.getYourActionLink()[0].url}}" class="btn detail-link__btn">{{::modalIssue.issue.getYourActionLink()[0].copy}}</a>
<a ng-if="::modalIssue.issue.getYourActionLink().length > 1" ng-repeat="link in ::modalIssue.issue.getYourActionLink()" href="{{link.url}}" class="detail-link__multiple">{{link.copy}}<span class="icon-arrow-right"></span></a>
</section>
Thank you in advance for any assistance that can be provided here.
So, turns out :: in Angular templates defines a one-time binding. This essentially means that as soon as, for example, the following expression has been run:
{{::modalIssue.issue.getTitle()}}
and it returned a value that is not undefined, it is considered stable and the expression will never be run again. So, removing :: from each of the relevant lines in the template resolved the issue.
Docs: https://docs.angularjs.org/guide/expression (#see One-Time Binding)

Is it possible to reference Angular custom directive inside itself?

Looking to implement folder hierarchy in Angular:
I'm implementing this via custom directive that references itself inside its template.
Currently it's going into infinite loop with this setup:
<!-- index.html -->
<subfolders folder="default_folder"></subfolders>
This is the <subfolders> directive:
//subfoldersDirective.js
angular.module('app').directive('subfolders', subfolders);
function subfolders() {
var directive = {
restrict: 'AE',
scope: {
folder: '=',
},
templateUrl: '/pathto/subfoldersDirective.html',
controller: DirCtrl,
controllerAs: 'vm'
};
return directive;
function DirCtrl($scope) {
var vm = this;
vm.folder = $scope.folder;
}
}
and its template:
<!-- folderDirective.html -->
<div ng-repeat="folder in vm.folder.subfolders">
{{ folder.name }}
<button ng-click="folder.is_open = true">Open folder</button>
<div ng-if="folder.is_open">
<!-- This is the problem line -->
<subfolders folder="folder"></subfolders>
</div>
</div>
In the template, <subfolders> should only get rendered after the button is clicked which triggers ng-if="folder.is_open". I guess Angular does not know this when it compiles the directive. It goes into infinite loop, even though it technically should not.
Is there a way to make it work with the directive? The logic is a bit more complex in the real app, this is why I'm looking to make it work with the directive.
I'm currently using Angular 1.2.26.
You can do this, but you need to override the compile behavior of the directive. You need to remove contents of the directive element during the compilation step, and then compile and reattach it during the post-link step. I have used the compile function below with great success:
function compile(element) {
var contents = element.contents().remove();
var contentsLinker;
return function (scope, iElement) {
if (angular.isUndefined(contentsLinker)) {
contentsLinker = $compile(contents);
}
contentsLinker(scope, function (clonedElement) {
iElement.append(clonedElement);
});
};
}
I based this function on this post, which is probably more comprehensive if you need a pre-link function.

ng-animate and custom diretives?

I am trying to add custom animation to my custom directive but failing why?
.directive('home', function ($animate) {
return {
templateUrl: 'views/pantone-inner-home.html',
restrict: 'AE',
link: function postLink($scope, element, $parent) {
var parentElement = element[0].parentElement;
var afterElement = element[0].parentElement;
$animate.enter(element, parentElement, afterElement);
$scope.PrevNext = 'open';
$scope.mainmenulink = '';
$('.top_left_logo.white img').css('position', 'fixed');
$('#focus_force').focus();
}
};
});
I then have a custom toggled ng-cluded that calls this in:
<a ng-click="closemenulink(element)" ng-href="#/services"><home class="pantone-ani"></home></a>
is just give me this everytime the ng-include includes this into the template:
TypeError: Object [object HTMLAnchorElement] has no method 'after'
why?
what does it need here:
I'm using this:
http://docs.angularjs.org/api/ngAnimate.$animate
PATNONE INNER HOME:
<div ng-click="pantone()" class="pantone_wrap_outer blue slide_bottom">
<div class="pantone_wrap_inner blue">
<div class="pantone blue">
<img src="images/services.png" alt="">
</div>
</div>
</div>
I'm trying to animate a menu with this and if i use ng-include to add these pantones ( there are 4) then after it's been opened and closed once it stays in the $templateCache so it doesn't add the "ng-enter" class after the second load which ruins my animations..
Please see the following plunker
http://plnkr.co/edit/v8aCQI59reemfiEwXICC?p=preview
I think the afterElement is null to you as there are no siblings with the element.
Please check the plunker and let me know if you need anything else.

AngularJS: Trying to programatically add directives to a view

Here is my plunk: http://plnkr.co/edit/BGD0n6gmDM3kv5akIn4l?p=info
I am trying to make a view factory of sort. Ideally my controller will place a config object into scope that the view will use to render the page. It will be used to build navigation and content. I am stuck while trying to dynamically pass directives/partial view references from this object.
Here is a isolated object from the config in my controller:
$scope.partials = [
{
name: 'Well',
method: 'showWell()',
isVisible: false,
template: '<container-well></container-well>'
}
];
The focus of this question would be the template property. I built directives to function as partial views here.
Here is an example of one of my directives:
myApp.directive('containerWell', function() {
return {
restrict: 'E',
replace: false,
templateUrl: 'containers/well.html',
scope: {}
}
});
And here is the well.html template file:
<div>
<h2 class="special">Well Types</h2>
<div class="well well-cc">
<p>Closed Well</p>
<p>CSS: .well.well-cc</p>
</div>
<div class="well well-cc open">
<p>Open Well</p>
<p>CSS: .well.well-cc.open</p>
</div>
<h3 class="alt">Wells can have different highlights applied with css classes</h3>
<div class="well well-cc highlight-warning">
<p>CSS: .well.well-cc.highlight-warning</p>
</div>
</div>
Here is the code in my view that I am failing with:
<div ng-repeat="partial in partials" ng-bind-html-unsafe="{{partial.template}}"></div>
The generated markup looks like this:
<div class="ng-scope" ng-bind-html-unsafe="<container-well></container-well>" ng-repeat="partial in partials"></div>
Its just basically adding the string tag to the attribute instead of the directive.
Basically, I would like to be able to programatically add directives to my view. I am not sure if what I am trying to do is even possible. I am not confident that passing the string equivalent of the directive is the way to go. I would love some suggestions or even some stern correction if I am being ridiculous; well not too stern, maybe something constructive ;)
Here is my plunk: http://plnkr.co/edit/BGD0n6gmDM3kv5akIn4l?p=info
Thanks,
Jordan
You have to $compile the dynamic template. See the example in the docs. I forked your plunk to demonstrate the case:
http://plnkr.co/edit/WBT9FbZmvp0Xj0LAAPzk?p=preview
The points are:
ng-bind-html-unsafe is unsuitable for this usage.
Create another directive to compile the dynamic template, just as in the example:
Compilation is actually quite easy:
MyApp.directive("myDir", function($compile) {
return {
link: function(scope, elem, attrs) {
scope.$watch(
function(scope) {
return scope.$eval(attrs.myDir);
},
function(value) {
var e = $compile(value)(scope);
elem.contents().remove();
elem.append(e);
}
);
}
};
});
Use it as:
<div ng-repeat="partial in partials">
<div my-dir="partial.template"></div>
</div>

Categories

Resources