ng-animate and custom diretives? - javascript

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.

Related

Passing data between controllers during initialization with $rootScope.$emit

I have a common module with a controller, component and template combo for initialisation purposes and defining the base layout of the app. I then have a stateful component that on initialisation makes a HTTP GET requests to fetch a background image from an API. Once the promise is resolved, I use $rootScope.$emit to fire an event back up to the common controller with the image URL so that it can be set as the background image of the app dynamically.
What I can't get my head around is that when console logging the event response inside the $rootScope.$on() function shows me the result, but anywhere else inside in the controller yields nothing (inside $onInit() or anywhere else).
What's more baffling is that I can render the event data in the Common controller's template no problem, be it inside an input box with ng-model or inside a paragraph. When I try to concatenate it as part of my inline CSS or background-image directive however, it's not picked up whatsoever. The directive returns the URL up to the variable name (https://image.tmdb.org/t/p/original) then cuts off.
Any suggestions would be really really appreciated!
This is the component controller code:
function MovieDetailController(MovieService, $rootScope){
var ctrl = this;
ctrl.$onInit = function(){
// Get all additional data
MovieService
.getAdditionalData(ctrl.movie.movie_id)
.then(function(response){
ctrl.actors = response.credits.cast.splice(0, 6);
ctrl.extras = response.videos.results.splice(0, 3);
ctrl.similar = response.similar.results.splice(0,6);
ctrl.backdrop = response.backdrop_path;
$rootScope.$emit('backdropChange', ctrl.backdrop);
});
}
}
angular
.module('components.movie')
.controller('MovieDetailController', MovieDetailController)
And this is the Common Controller code
function CommonController($state, $rootScope){
var ctrl = this;
$rootScope.$on('backdropChange', function(event, data){
ctrl.backdrop = data;
// Displays result successfully
console.log('Back drop is ' + ctrl.backdrop);
});
ctrl.$onInit = function(){
// Doesn't log result
console.log('On Init, Backdrop is ' + ctrl.backdrop);
}
}
angular
.module('common')
.controller('CommonController', CommonController);
Here is the HTML template for the Common Controller
<header class="row" id="topnav">
<topnav class="col-sm-12 p-3 d-inline-flex"></topnav>
</header>
<!-- Testing if data is rendered inside the input box and it is! -->
<div class="col-sm-12"><input type="text" name="" ng-model="$ctrl.backdrop"></div>
<!-- Directive only receives first part of URL up to variable then cuts off-->
<main class="row" id="main-body" back-img="https://image.tmdb.org/t/p/original{{$ctrl.backdrop}}">
<aside class="flex-fixed-width-item bg-white" id="sidebar">
<sidebar></sidebar>
</aside>
<section class="col" id="content-window">
<!-- Filters and Main Section Submenu -->
<div class="row">
<nav class="col-sm-12 filter-container">
<div ui-view="details-menu"></div>
</nav>
</div>
<!-- Main Content Section -->
<div ui-view="details" class=""></div>
</section>
</main>
Last but not least the background image directive
function backImg(){
return {
link: function(scope, element, attrs){
var url = attrs.backImg;
element.css({
'background-image': 'url(' + url +')'
});
}
}
}
angular
.module('common')
.directive('backImg', backImg);
The backImg directive should $observe the attribute:
function backImg(){
return {
link: function(scope, element, attrs){
attrs.$observe("backImg", function(url) {
element.css({
'background-image': 'url(' + url +')'
});
});
}
}
}
From the Docs:
$observe(key, fn);
Observes an interpolated attribute.
The observer function will be invoked once during the next $digest following compilation. The observer is then invoked whenever the interpolated value changes.
— AngularJS Attributes API Reference - $observe

ng-else directive in angularjs

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

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)

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>

Preventing image from rendering in AngularJs

I have this jsFiddle:
http://jsfiddle.net/HMZuh/1/
Which contains this html
<div ng-app ng:controller="ShowHideController">
<div ng-show='showMe'>
<img ng-src="{{imageSource}}"/>
</div>
<button ng-click='showImage()'> show image </button>
<div>
and this script:
function ShowHideController($scope) {
$scope.showMe = false;
$scope.imageSource = '';
$scope.showImage = function(){
$scope.showMe = true;
$scope.imageSource = 'https://www.google.com/images/srpr/logo3w.png';
}
}
I'm getting a 404, image not found when the source has not yet been set, is there any way of preventing this when showMe is false?
​
To solve this you can:
Use ng-repeat http://jsfiddle.net/bGA4T/
Use $compile and declare your own directive
Write your own ng-src directive
...
I think there are many ways to solve this.
I improved on this by using ui-if from http://angular-ui.github.com/
Instead of hiding/showing using ng-hide/ng-show, ui-if simply does not render the element.
<div ui-hide='ImageHasBeenUploaded'>
<img ng-src='/some/image/path/{{imageName}}/>
</div>

Categories

Resources