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>
Related
So I have a parent component, that hosts 2 sibling components.
something like this
<div *ngif="somecode()">
<sibling1>
</sibling1>
</div>
<div *ngif="somecode()">
<sibling1 [dataParams]=sibling1object.somedata>
</sibling1>
</div>
so I get the error that sibling1object.somedata is undefined but when I remove ngIf() from 1st div, the error disappears.
It doesn't matter if *ngIf resolves to true or false. so i get the error even when sibling1 successfully loads.
Use [hidden]="!somecode()" instead of *ngIf="somecode()"
Please add following code in parent.component.ts
public siblingOneLoaded: boolean = false;
ngOnDestroy(): void {
if (sibling1object.somedata) {
this.siblingOneLoaded = true;
}
}
Add following code to html file
<div *ngIf="siblingOneLoaded">
<sibling1 [dataParams]=sibling1object.somedata>
</sibling1>
</div>
I'm working on a site, and I started building it before I realized I needed some dynamic framework. After learning about AngularJS, I decided to use it, where I needed (not the whole site).
I have a very long script in JS, and I want to be able to get and set the variables from within AngularJS directives and controllers.
I found this answer, and it was quite good - I was able to get the variable from within the function. But when the variable changed outside the function, AngularJS' variable won't update.
My code looked something like this:
JS:
var app = angular.module('someName', []);
var currentPage = 'Menu';
app.controller('PageController', ['$window','$scope', function($window,$scope){
this.currentPage = $window.currentPage;
this.isPage = function(page){
return (page == this.currentPage);
};
}]);
function button1onClick(){
currentPage = 'Game';
}
HTML:
<div ng-controller="PageController">
<div id="Game" ng-show="page.isPage('Game')">
...
</div>
<div id="Menu" ng-show="page.isPage('Menu')">
...
</div>
</div>
(button1onClick was called when I clicked some button on the page)
The idea is that I have two dives I want to switch between, using a globle variable. 'Menu' page was visible at first but upon clicking I was supposed to see only the 'Game' div.
The variable inside the controller didn't upadte, but was only given the initial value of currentPage.
I decided to use the $window service inside the isPage function, but this didn't work either. Only when I called a function that tested the $window.currentPage variable, the pages switched - like I wanted:
JS:
var app = angular.module('someName', []);
var currentPage = 'Menu';
app.controller('PageController', ['$window','$scope', function($window,$scope){
this.isPage = function(page){
return (page == $window.currentPage);
};
this.button2onClick = function() {
$window.alert($window.currentPage);
}
}]);
function button1onClick(){
currentPage = 'Game';
}
HTML:
<button onclick="button1onClick()">CLICK ME</button> //Button 1
<div ng-controller="PageController">
<button ng-click="page.button2onClick">CLICK ME</button> //Button 2
<div id="Game" ng-show="page.isPage('Game')">
...
</div>
<div id="Menu" ng-show="page.isPage('Menu')">
...
</div>
</div>
So the only way I was able to update the pages is to call a function that tests the variable, thus updating the variable in AngularJS.
Is there a way to access a global variable without needing to test it to update it?
Am I doing something wrong? I don't want to convert my whole site to AngularJS-style, I like the code the way it is. Is AngularJS not the framework for me?
EDIT:
some things to clear out:
I'm new to AngularJS, so if you could explain what your answer does it would be great.
The whole reason why I do this instead of redirecting to another page is not to shut down socket.io 's connection
OP, take a look at UI Router.
var app = angular.module("app", ['ui.router']);
app.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/main');
$stateProvider.state('main', {
controller: 'MainCtrl',
templateUrl: 'main.html',
url: '/main/'
}).state('game', {
controller: 'GameCtrl',
url: '/game/',
templateUrl: 'game.html'
});
}]);
HTML links:
<a ui-sref="main">Go to Main</a>
<a ui-sref="game">Go to Game</a>
View injection
<div ui-view="">
</div>
You should not use $window as a map object.
You should probably create a PageService:
angular.module('someName')
.factory('Page', [function(){
var currentPage = 'Menu';
return {
getPage: function() {
return currentPage;
},
isPage: function(page) {
return page === currentPage;
},
setPage: function(page) {
currentPage = page;
}
}
}]);
app.controller('PageController', ['Page','$scope', function(Page,$scope){
this.currentPage = Page.getPage();
this.isPage = Page.isPage;
this.button10Click = function(){
Page.setPage('Game');
}
}]);
HTML
<div class="button" ng-click="page.button10Click()">Game</div>
After reading malix's answer and KKKKKKKK's answer, and after researching a bit, I was able to solve my problem, and even write a better looking code.
To switch divs as I wanted in the example, I used ui-router, almost exactly the way KKKKKKKK did. The only difference is that I change state programmaticly - $state.go('menu')
To access global variables in other places in my code, I had to re-structure my whole code to fit AngularJS's structure, and used a Service, similarly to malix's answer:
app.factory('Data', function(){
var Data = {};
//DEFINE DATA
Data.stateChange = function(){};
Data.menuData = {};
Data.randomColors = ['#35cd96', '#6bcbef', '#E8E1DA', '#91ab01'];
/RETURN DATA
return Data;
});
It can be done using $rootScope. Variable initialize once can be accessible in other controllers.
function Ctrl1($scope, $rootScope) {
$rootScope.GlobalJSVariableA= window.GlobalJSVariable; }
Any controller & any view can access it now
function CtrlN($scope, $rootScope) {
$scope.GlobalJSVariableA= $rootScope.GlobalJSVariableA;
}
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
I'm newbie to protractor framework, and I've been trying for a while to figure out how to get the outerHTML/InnerHTML/getText() (child elements) so that I can test if an element <img> is rendered onto a view. Heads up, we've an ng-grid and I'm trying to look up in its first column to see if it contains an img element also check if it contains an attribute i.e. src=res/someImg.png.
Here is what I got
html
<div>
<a>
<div>
<div>
<span>
<i><img src="res/someImg.png"></i>
</span>
</div>
<div>
...
</div>
<div>
...
</div>
</div>
</a>
</div>
test
it('should render an icon in agent list', function () {
var row = element.all(by.repeater('row in renderedRows')).get(3);
expect(row).not.toEqual(null); //pass
expect(row.element(by.css('img')).getAttribute('src').getText()).toMatch(/someImg.png/);//fail with null
expect(row.element(by.css('span')).outerHTML).toBe('<i><img src="res/someImg.png"></i>'); //fails
expect(row.element(by.css('i')).innerHTML).toBe('<img src="res/someImg.png">'); //fails
});
Can someone tell what am I doing wrong please?
Use getAttribute() in all 3 cases - for src, outerHTML and innerHTML:
expect(row.element(by.css('img')).getAttribute('src')).toMatch(/someImg.png/);
expect(row.element(by.css('span')).getAttribute('outerHTML')).toBe('<i><img src="res/someImg.png"></i>');
expect(row.element(by.css('i')).getAttribute('innerHTML')).toBe('<img src="res/someImg.png">');
Tested - works for me.
A little more explicitly:
expect(row.element(by.css('img')).getAttribute('src')).toMatch(/someImg.png/);
expect(row.element(by.css('span')).getOuterHtml()).toBe('<i><img src="res/someImg.png"></i>');
expect(row.element(by.css('i')).getInnerHtml()).toBe('<img src="res/someImg.png">');
As alecxe said on Aug 24 '16, "getOuterHtml() and getInnerHtml() are now deprecated in WebDriverJS and Protractor" (see comment from https://stackoverflow.com/a/27575804/3482730)
You should now use the following to get innerHTML code (as indicated here: https://github.com/angular/protractor/issues/4041#issuecomment-372022296):
let i = browser.executeScript("return arguments[0].innerHTML;", element(locator)) as Promise<string>;
Example using a helper function:
function getInnerHTML(elem: ElementFinder): Promise<string> {
return getInnerHTMLCommon(elem, elem.browser_);
}
function getInnerHTMLCommon(elem: WebElement|ElementFinder, webBrowser: ProtractorBrowser): Promise<string> {
return webBrowser.executeScript("return arguments[0].innerHTML;", elem) as Promise<string>;
}
const html = await getInnerHTML(browser.element(by.xpath("div[1]")));
console.log(html);
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.