I tried the ng-class directive with a ternary and it works very well when the page load. My reference is the widthWindow.xs variable, it is "true" when the window size is a mobile, but there is a resize put it to "false" but the class does not change, the ng-class not dynamically changes. Why?
in the controller:
$scope.myResize = funcion(){
var number = $window.innerWidth;
if (number > 767) {
$scope.widthWindow.xs = false;
}else{
$scope.widthWindow.xs = true;
}
};
in the html:
<p ng-class="widthWindow.xs ? 'borderVoteNewsTop' : 'borderVoteNewsLeft'">Don't change when there is a resize</p>
Since the 'resize' event comes form outside the Angular framework, you need to integrate its actions with the AngularJS digest cycle. Use $apply.
$scope.myResize = function(){
var number = $window.innerWidth;
if (number > 767) {
$scope.$apply("widthWindow.xs = false");
}else{
$scope.$apply("widthWindow.xs = true");
}
};
After the $apply executes the Angular expression, it will automatically invoke a digest cycle and the watcher in the ng-class directive will see the change and update the class.
Your syntax for the ngClass directive is not correct.
Use it as following:
<p
ng-class="{'borderVoteNewsTop': widthWindow.xs, 'borderVoteNewsLeft': !widthWindow.xs}"
>
Change when there is a resize
</p>
Check out the directive documentation: https://docs.angularjs.org/api/ng/directive/ngClass
Related
I'm new in angular and i'm looking for the best way to do what I want.
In my main page I have 2 directives, one is used to display a button (and maybe other stuff). And another used to display a kind of dialog box/menu.
Each directive has its own controller.
I want to show or hide the second directive when I click on the button in the first one.
I don't really know what are goods or wrong approaches. Should I use a service injected in both controller and set a variable with ng-show in the second directive? This solution doesn't really hide the directive because I need a div inside the directive to hide its content and isn't too much to use a service only for one boolean?
Should I use a kind of global variable (rootscope?) or inject the first controller inside the second one?
Or maybe use a third controller in my main page (used with a service?) or use only one controller for both directive?
Basically without directive I would probably used only one main controller for my whole page and set a variable.
In fact the first directive is just a kind of button used to display "something", and the second directive just a kind of popup waiting a boolean to be displayed. That's why I finally used a service containing a boolean with a getter and a setter to avoid any interaction beetween both controller.
My both controller use this service, the first one to set the value when we click on the element and the second controller provide just a visibility on the getter for my ng-show.
I don't know if it is the best way to do but I am satisfied for now.
Small example here (without directive but with same logic) :
http://codepen.io/dufaux/pen/dXMrPm
angular.module('myModule', []);
angular.module("myModule")
.controller("ButtonCtrl", buttonCtrl)
.controller("PopUpCtrl", popUpCtrl)
.service("DisplayerService", displayerService);
//ButtonCtrl
buttonCtrl.$inject = ["DisplayerService", "$scope"];
function buttonCtrl(DisplayerService, $scope) {
var vm = this;
vm.display = function(){
DisplayerService.setDisplay(!DisplayerService.getDisplay());
}
}
//PopUpCtrl
popUpCtrl.$inject = ["DisplayerService"];
function popUpCtrl(DisplayerService) {
var vm = this;
vm.displayable = function(){
return DisplayerService.getDisplay();
}
}
//Service
function displayerService(){
var vm = this;
vm.display = false;
vm.setDisplay = function(value){
vm.display = value;
}
vm.getDisplay = function(){
return vm.display;
}
}
--
<body data-ng-app="myModule">
<div data-ng-controller="ButtonCtrl as btnCtrl" >
<button data-ng-click="btnCtrl.display()">
display
</button>
</div>
[...]
<div data-ng-controller="PopUpCtrl as popUpCtrl" >
<div data-ng-show="popUpCtrl.displayable()">
hello world
</div>
</div>
</body>
I have an AngularJS Application with a scroll directive implemented as the following:
http://jsfiddle.net/un6r4wts/
app = angular.module('myApp', []);
app.run(function ($rootScope) {
$rootScope.var1 = 'Var1';
$rootScope.var2 = function () { return Math.random(); };
});
app.directive("scroll", function ($window) {
return function(scope, element, attrs) {
angular.element($window).bind("scroll", function() {
if (this.pageYOffset >= 100) {
scope.scrolled = true;
} else {
scope.scrolled = false;
}
scope.$apply();
});
};
});
The HTML looks the following:
<div ng-app="myApp" scroll ng-class="{scrolled:scrolled}">
<header></header>
<section>
<div class="vars">
{{var1}}<br/><br/>
{{var2()}}
</div>
</section>
</div>
I only want the class scrolled to be added to the div once the page is scrolled more than 100px. Which is working just fine, but I only want that to happen! I don't want the whole scope to be re-rendered. So the function var2() should not be executed while scrolling. Unfortunately it is though.
Is there any way to have angular only execute the function which is bound to the window element without re-rendering the whole scope, or am I misunderstanding here something fundamentally to AngularJS?
See this fiddle:
http://jsfiddle.net/un6r4wts/
Edit:
This seems to be a topic about a similar problem:
Angularjs scope.$apply in directive's on scroll listener
If you want to calculate an expression only once, you can prefix it with '::', which does exactly that. See it in docs under One-time binding:
https://docs.angularjs.org/guide/expression
Note, this requires angular 1.3+.
The reason that the expressions are calculated is because when you change a property value on your scope, then dirty check starts and evaluates all the watches for dirty check. When the view uses {{ }} on some scope variable, it creates a binding (which comes along with a watch).
The app has a controller, that uses a service to create an instance of video player. The video player triggers events to show progress every few seconds. When the video reaches to a certain point, I want to show a widget on top of the video player.
The view has the widget wrapped in ng-show directive.
It takes more then 60 seconds for the dom element to receive the signal to remove the ng-hide class after the event has been triggered and the values have been populated.
If I try to implement this using the plain dom menthod (like document.getElementById(eleId).innerHTML = newHTML), the update is instant.
What am I doing wrong? Here is the complete sequence in code:
Controller:
MyApp.controller('SectionController', ['$scope', 'PlayerService'], function($scope, PlayerService){
$scope.createPlayer = function() {
PlayerService.createPlayer($scope, wrapperId);
}});
Service:
MyApp.service('PlayerService', [], function(){
this.createPlayer=function(controllerScope, playerWrapper){
PLAYER_SCRIPT.create(playerWrapper) {
wrapper : playerWrapper,
otherParam : value,
onCreate : function(player) {
player.subscribe(PLAY_TIME_CHANGE, function(duration){
showWidget(controllerScope, duration);
})
}
}
}
function showWidget(controllerScope, duration) {
if(duration>CERTAIN_TIME) {
$rootScope.widgetData = {some:data}
$rootScope.showWidget = true;
}
}});
View:
<div ng-show="showWidget"> <div class="wdgt">{{widgetData.stuff}}</div> </div>
Solved it! $scope.$apply() did the trick.
My guess is, due to other complex logic ad bindings inside the app, there was a delay in computing the change by angular the default way.
#floribon Thanks for the subtle hint about "complex angular stuff".
The code inside the service function changed to:
function showWidget(controllerScope, duration) {
if(duration>CERTAIN_TIME) {
$rootScope.widgetData = {some:data}
$rootScope.showWidget = true;
$rootScope.$apply();
}}
Do you have complex angular stuff within your hidden view?
You should try to use ng-if instead of ng-show, the difference being that when the condition is false, ng-if will remove the element from the DOM instead of just hidding it (which is also what you do in vanilla JS).
When the view is simply hidden using ng-show however, all the watchers and bindings within it keep being computed by Angular. Let us know if ng-if solve your problem, otherwise I'll edit my answer.
This is my url - charts/53d25d91959679701e362f25 and when I add ?widget=true to that link charts/53d25d91959679701e362f25?widget=true I have to hide two particular divs in charts/53d25d91959679701e362f25 page.
I've tried - ng-if="location.path()" but is not working for ?widget=true
You cannot use $location service in ng-if directive
User $location to set some scope and tie ng-if to that scope variable.
if(angular.isDefined($location.search().widget)) {
$scope.isHidden = true;
}
else {
$scope.isHidden = false;
}
ng-if="isHidden"
When my application loads or fetches data I add an entry to an array called "loading"
I then have the following that displays in my status bar:
<span data-ng-repeat="load in loading">|</span>
It shows a vertical bar for every item loading.
Is there a way that I could also change my cursor so that when there's some loading
activity (when loading.length > 0) then the cursor changes to :
cursor:wait;
If you are using ui.router, you can use the $stateChangeStart, $stateChangeSuccess and $stateChangeError to trigger when and when not to show the loading cursor. If you are using routes, simply use $routeChangeStart, $routeChangeSuccess and $routeChangeError in replacement.
//loading controls
document.body.style.cursor='default';
$scope.$on('$stateChangeStart', function() {
document.body.style.cursor='wait';
});
$scope.$on('$stateChangeSuccess', function() {
document.body.style.cursor='default';
});
$scope.$on('$stateChangeError', function() {
document.body.style.cursor='default';
});
You can also use these state changes to trigger a loading icon.
//loading controls
$scope.isViewLoading = false;
document.body.style.cursor='default';
$scope.$on('$stateChangeStart', function() {
$scope.isViewLoading = true;
document.body.style.cursor='wait';
});
$scope.$on('$stateChangeSuccess', function() {
$scope.isViewLoading = false;
document.body.style.cursor='default';
});
$scope.$on('$stateChangeError', function() {
$scope.isViewLoading = false;
document.body.style.cursor='default';
});
<span class="spinner" ng-show="isViewLoading">Loading...</span>
You can use ng-style or ng-class
For example, create custom style:
$scope.state = 'wait';
$scope.mySyle = {
'cursor': state
}
Now, we can change our $scope.state during the time and out style will change respectively.
For ng-class - the same thing, just create style into css file and switch ng-class value.
Here is a references:
ng-class - use when the set of CSS styles is static/known ahead of time
ng-style - use when you can't define a CSS class because the style values may change dynamically. Think programmable control of the style values.
(took from THIS POST)