What am i missing here? Angularjs ionic sliders - angularjs

I am using the sliders in the ionic framework and everything is working great. This is my html:
<ion-slide-box on-slide-changed="slideHasChanged($index)" show-pager={{showPager}}>
Pretty straightforward, notice that i am using showPager to dynamically show and hide the pager.
And in the controller:
$scope.showPager = true
$scope.slideHasChanged = ($index) ->
if $index == 4
$scope.$apply ->
$scope.showPager = false
It does as expected sets showPager value to false when the index of the slide is 4 in the web console.
BUT it does not really hide it on the web page. IF i explicitly set showPager to false, it does not display in the browser as expected, but if i try the above stuff to dynamically hide it, it does not work.
What am i missing?

<ion-slide-box> directive does not observe show-pager attribute. So it will consider only the value which was at the time of directive initialization.
For your use-case, you can show/hide pager by putting ng-class directive on <ion-slide-box> directive and based on that class you can write css to show/hide the pager.
Check this example codepen for working example.

Related

How do I dynamically style uib-accordion-group

I have created a uib-accordion in my Angular website and can get most of the functionality I want, with dynamic content changing accordingly.
I am having trouble styling the uib-accordion-group dynamically.
<uib-accordion-group panel-class="panel-danger">
<uib-accordion-heading>
Accordion Heading 1
Is fine and colours the whole heading Red/Pink, I want to change this to panel-warning or panel-info based on other variables on the page.
<uib-accordion-group panel-class="{{getPanelColor()}}">
<uib-accordion-heading>
Accordion Heading 1
The function seems to be called correctly and is triggered correctly with ng-click elsewhere.
I appears that I cannot change the value panel-class uses dynamically. So in this instance getPanelColor() returns 'panel-danger', 'panel-info' or 'panel-warning' depending on other variables. If I print this return value out on the page in another div or whatever it changes correctly. If I refresh the page the correct colours are displayed for the changed panel-group.
Is there another way of setting the color - I don't know what the classes are for the accordion-group. I have tried changing the color of a div withing the panel, but this is a child element and does not change the color of the whole heading.
Any help much appreciated. (I'll come up with a JSFiddle if the question is not clear)
If you look at the HTML after the panel-class has changed and Angular has digested the change, you will see this line:
<div class="panel panel-danger" ... panel-class="panel-default">
That is, there is a mismatch between class and panel-class (the former has panel-danger, whereas the latter has panel-default). The uib-accordion-group directive simply does not handle the change in the wanted manner.
One workaround is to add ng-if to the whole group:
<uib-accordion-group ng-if="render" panel-class="{{getPanelColor()}}">
... and just before you want to change panel-class, remove the whole element temporarily, so that Angular re-renders it from scratch. Hopefully, the following code explains the principle:
$scope.render = true;
$scope.panelColor = 'panel-danger';
$scope.setPanelColor = function(val) {
$scope.panelColor = val;
$scope.render = false;
$timeout(function () {
$scope.render = true;
});
};
$scope.getPanelColor = function() {
return $scope.panelColor;
};
See the proposal in action: http://plnkr.co/edit/XfJiPnNi1z4F9cgIVxxw?p=preview. Press 'Clear panel color OK'.
The downside is that the removal of the element causes some flickering.
I have added another button 'Clear panel color FAIL' that shows what happens in your failing case. Here is what the HTML looks like after you press the button, notice the mismatch panel-danger vs. panel-default:
Use an interpolated expression in the class attribute, for example:
class="{{!ctrl.valid?'notValid':'valid'}}"

How to update value in template Angular JS?

I use Angularjs on page for displaying numbers of notes:
<span ng-hide="currentCount.messages <= 0">{{currentCount.messages}}</span>
The value currentCount.messages is got from response AJAX in controller.
Problem is that when I do reflesh browser page I see text {{currentCount.messages}} temporarily.
I tried to define in top controller: $scope.currentCount.messages = 0; but it did not help me.
Try this:
<span ng-hide="currentCount.messages <= 0" ng-bind="currentCount.messages"></span>
Using ng-bind accomplishes the same thing, but you won't see the template string in the page before the angular finishes rendering.

Angular: Fading out element and then setting display none

When I click an element, I'd like another element to first fade out, and then be set to display: none.
I have the following code:
Partial:
<div class="main_menu_image" ng-class="{ fadeOut : MenuOpen==true }" /></div>
<div class="button" ng-click="ActivateMenu()"></div>
Then in my controller:
$scope.MenuOpen = false;
$scope.ActivateMenu = function(){
$scope.MenuOpen = $scope.MenuOpen === false ? true: false;
}
So when I click the button, element main_menu_image gets the class fadeOut. So it now fades out. But after the fading animation completes I would also like to set display to none on main_menu_image so it is completely hidden.
I don't want to resort to jQuery. Is there an Angular approved way of doing this?
Yes it's very easy to do:)
Like Svein says, you can use ng-show, and you can use ng-hide.
Working fiddle here
This hides things instantly though. But you can for example set a timeout, via the $timeout service, and set your hiding boolean in that way.
You can also use ng-if, this actually removes the element from the DOM if the condition is not met, rather than just setting display:none.
Update: Here's a more proper fiddle showcasing what you're trying to do
You can use ngShow. If you use the ngAnimate module, you'll have built in support for animations for most built-in Angular directives.
See here for more information:
https://docs.angularjs.org/guide/animations

AngularJS using ng-if vs ng-show

In my AngularJS I have the following code where I check if there is a currently logged in user or not in order to switch the top app menu text from Login to Logout (login if no user is logged in) and vice versa. When I used ng-show ng-hide the app started to be extremely heavy so I tried switching to ng-if, but then the css effects on the top menu started not to work specifically in the login/ logout tab. So can someone please tell me what is the best approach to handle this situation with example please? Thanks
index.html
<div ng-controller="MenuController">
<li>
<div ng-if="userLevel() == 1">
Login
</div>
<div ng-if="userLevel() == 2">
Logout
</div>
</li>
</ul>
</div>
Controller:
controller('MenuController',
function MenuController($scope, UService){
$scope.userLevel = function(){
var userType = UService.checkULevel(); //This will return either 1, 2,3,4...etc
return userType;
};
});
The difference between ng-show and ng-if is that ng-show applies a display: none to the element when the specified expression is a false value, while the ng-if removes the node from the DOM, basically equivalent to the .empty in jQuery.
An approach you can consider for your element, is rather than using it within a controller, use a directive for the access level, and follow the approach described in this article, which is really flexible and allows you to have different elements in the UI depending on the user level: http://frederiknakstad.com/2013/01/21/authentication-in-single-page-applications-with-angular-js/
Another reason for your application to be slow when you check the user level, could be that every time that is evaluated your application has to perform a check on the server side, slowing the application. An approach for it would be to cache the result of that query, and then use it while the login status doesnt change. At that stage you can invalidate the cache and fetch the user level again, ready to update the UI.
The ng-if directive removes the content from the page and ng-show/ng-hide uses the CSS display property to hide content.
I am pretty sure that no-show is lighter than ng-if and no-show should not make the app too heavy. If it is becoming heavy, I think there could be other causes for it.
If you use ng-if the node is rendered only when the condition is true
In case of ng-show ng-hide the Nodes will be rendered but shown/hidden based on the condition if condition changes the same nodes are shown/hidden
when ever you use ng-if it will render only that code which satisfy the condition.
while ng-show ng-hide will render the code on page but will be hidden with the help of CSS properties.
so better to use ng-if for reducing the line of code to be rendered on page.

What's a good way to control an angular-ui accordion programmatically?

I am using the accordion directive from http://angular-ui.github.com/bootstrap/ and I need to have more control over when the accordions open and close.
To be more precise I need a button inside the accordion-group that will close its parent accordion and open the next one (so basically mimic what clicking the next header would do if close-others was set to true).
I also need to do some validation before I can allow an accordion to be closed and the next one to be opened, and I also need to wire this up to click events on the accordion headers.
I am pretty new to angular and we're currently rewriting an application from Backbone+JQuery to Angular. In the Backbone-version we were using Twitter Bootstrap accordions and we were opening and closing them using JQuery. While we can still keep doing this I would rather get rid of JQuery DOM manipulation completely so I am looking for a pure angular solution to this.
What I've tried to do in terms of validation is
<accordion-group ng-click="close($event)">
and in my controller
event.preventDefault();
event.stopPropagation();
This obviously did not work as the DOM element is replaced by the directive and the click-handler is never added. I've been going over the source code (and found a few very nice undocumented features) but I'm at a loss over where to even begin solving this specific challenge. I was considering forking angular-ui and try to add this functionality to the accordion directive but if I can achieve this without modifying the directive that would be a lot nicer.
There is the is-open attribute on the accordion-group which points to a bindable expression. By using this expression you can control accordion items programatically, ex.:
<div ng-controller="AccordionDemoCtrl">
<accordion>
<accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.open">
{{group.content}}
</accordion-group>
</accordion>
<button class="btn" ng-click="groups[0].open = !groups[0].open">Toggle first open</button>
<button class="btn" ng-click="groups[1].open = !groups[1].open">Toggle second open</button>
</div>
and the working plunk here: http://plnkr.co/edit/DepnVH?p=preview
For whoever the solution by #pkozlowski.opensource is not working (me for example) you could just force the component to accept the CSS that will close it (without transition that is).
The Theory: The angular directive gets expanded into standard HTML, div elements mainly, where the CSS styles give it the appearance of the accordion. The div with class .panel-collapse is the body of the accordion-group element. You can swap its second class from .in to .collapse along with a few other changes as seen below.
The Code:
$scope.toggleOpen = function(project) {
var id = '<The ID of the accordion-group you want to close>';
var elements = angular.element($document[0].querySelector('#'+id));
var children = elements.children();
for(var i = 0; i < children.length; i++) {
var child = angular.element(children[i]);
if(child.hasClass('panel-collapse')) {
if(child.hasClass('in')) { // it is open
child.removeClass('in');
child.addClass('collapse');
child.css('height', '0px');
} else { // it is closed
child.addClass('in');
child.removeClass('collapse');
child.css('height', 'auto');
}
}
}
};
As we are talking about Angular, it is very possible that you are generating the accordion through an ng-repeat tag. In this case you can also generate the id's for the elements like:
<accordion-group ng-repeat="user in users"
is-disabled="user.projects.length == 0"
id="USER{{user._id}}">
Given a Mongoose model User, notice that the id I am giving is not user._id but has 'USER' appended in front. This is because Mongoose might generate id's that start numerically and querySelector does not like that ;-) go figure!

Resources