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
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
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
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)
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>
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>