Animation End event Zurb Foundation for apps - angularjs

I have a scroll up event and a scroll down event. I am trying to use FoundationAPI.animate to slideInUp a div on scroll up and then slideOutBottom on scroll down. The original state of the div has a class of hide because without scrolling - it lives off the bottom of the page. I have this working except for one problem. When the slideOutBottom animation is finished, the hide class no longer is in the div, so it shows after the slideOutBottom completes. I want it to stay hidden like it was at state 0.
Code:
$scope.scrollUp = function() {
if ($scope.lock == false ){
console.log('scrolling up');
$scope.lock = true;
FoundationApi.animate($('.footer-bar'), $state, "slideInUp", "hide");
console.log($state);
}
};
$scope.scrollDown = function() {
if ($scope.lock == true){
console.log('scrolling down');
$scope.lock = false;
FoundationApi.animate($('.footer-bar'), !$state, "hide", "slideOutBottom");
// setTimeout(function() {
// $('.footer-bar').addClass('hide');
// }, 999);
}
};
How do I access a callback for the FoundationAPI.animate(4) function such that it fires when it is complete? The commented out timeout works, but after the slideOutBottom finishes, the footer-bar appears, then the hide class gets applied. This causes the div to blink quickly. Anyone? The documentation on FoundationApi is lacking right now...

Not an answer but a solution. This a more natural AngularJS approach:
Controller:
function myController($scope, ...) {
$scope.lock = false;
$scope.scrollUp = function() {
if ($scope.lock == false ){
$scope.lock = true;
$scope.$apply();
}
};
$scope.scrollDown = function() {
if ($scope.lock == true){
$scope.lock = false;
$scope.$apply();
}
};
}
View:
<a id="footer" class="slideInUp slideOutBottom footer-bar" ng-hide="lock" zf-open="myModal">
<div>Click Me</div>
</a>
So the scroll events I bind with a directive on the particular view container; this determines the logic for when we detect the scroll up/down events. From the directive I call these functions that are defined the scoped controller (above). These are bound 2-ways with the "lock" variable accessible in this scope.
Note that the way the animations are triggered are with the classes in the anchor. I think there are defined enter animations and defined exit animations which are both present in the class. So ng-hide kicks in depending on the boolean value of the $scope.lock variable in my controller.
Totally not clear - I guess would be more clear to an Angular expert

Related

ng-show and/or ng-if do not function 100% of the time

I have a Chrome extension uses an ng-show expression that checks a variable of Chrome storage, and displays a big blue button if the value is at zero. When opening the extension, however, the button could show up on the first click, or you may have to close and reopen the extension several times before it shows up (simply showing a blank body). This has been incredibly frustrating and is obviously a UX problem that I would like to fix before I publish the extension to the public.
Here is the div code from within the main view of the extension:
<div id="no_vseeks" ng-show="vseeks.length === 0">
<div class="big-button-container"><h1>CREATE</h1></div>
</div>
The expression is referring to an array called 'vseeks' in the Chrome local storage.
And here is what the extension is supposed to output:
But this is what the extension will show (seemingly) at random.
Please inform me if I need to include more code or images.
EDIT: Here's the main controller where the vSeeks array is being retrieved from Chrome storage. The console logs show that after the chrome.storage.get function is called, the array is present, but yet I still get a blank view.
app.controller('mainController', function($scope, $window) {
$scope.toggleAcc = function($event) {
var currentAcc = $event.currentTarget;
currentAcc.classList.toggle("active");
var panel = currentAcc.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
}
$scope.sendID = function(id) {
currentVID = id;
$window.location.href = "#!delete";
}
var noVseeks;
var home_button;
var newV_button;
console.log('controller reached', $scope.vseeks);
chrome.storage.sync.get('userData', function(items){
$scope.vseeks = items.userData.vSeeks;
console.log('inside chrome storage get', $scope.vseeks);
home_button = document.getElementById('home_button');
newV_button = document.getElementById('newV_button');
console.log('variables: ', home_button, newV_button);
if ($scope.vseeks.length < 1) {
home_button.style.visibility = "hidden";
newV_button.style.visibility = "hidden";
}
else {
newV_button.style.visibility = "visible";
if (home_button.style.visibility == "visible") {
home_button.style.visibility = "hidden";
}
}
});
});
I am unfamiliar with Chrome.storage.sync but it must be returning a non-angularjs promise (i.e. not $q). In that scenario, the function you are running upon resolve is executing outside of the angular digest cycle -- angular doesn't know it should be doing anything. The way to force angular to run its cycle is to use $scope.$apply. This will synchronize the model to the view and vice versa.

Get vis.js networkEvents from the controller

I need to use click event in my controller.
The networkEvents are created in angular-vs.js directive and I need it in my controller to trigger the click event of individual nodes.
This is a code snippet I'm using but it does seem to work:
$scope.networkEvents = { onload:function(network){ alert("Clicked"); } }
Thanks,
Here is my plunker.
index.html
It looks like you don't set your events attribute of the vis-network directive, so I think you meant:
<vis-network data="data" options="options" events="networkEvents" height="100%"></vis-network>
angular-vis.js
Also, in the onload callback of the vis-network directive (line 151) you're passing graph into the onload function, but it isn't defined. (Maybe it's supposed to be network instead?):
// onLoad callback
if (scope.events != null && scope.events.onload != null &&
angular.isFunction(scope.events.onload)) {
scope.events.onload(network);
}
script.js
With the above changes, the onload function seems to work as expected. Since you've already set up the forEach loop to attach the events, to get the click event you just need to add it to the networkEvents object:
$scope.networkEvents =
{
onload: function(network){
alert("I'm loaded");
},
click: function(clicked) {
alert("id: " + clicked.nodes[0] + " was clicked");
}
}

How to hide the menu icon when back button is shown?

I have a side menu with:
<ion-side-menus enable-menu-with-back-views="true">
So it is accesable from each view of my app. So now when there is a back view i have a back icon AND the menu icon in the top left nav-bar. How can i disable the menu-icon when there is a back-icon?
The method from here:
$scope.$on('$ionicView.beforeEnter', function (e, data) {
if (data.enableBack) {
$scope.$root.showMenuIcon = false;
} else {
$scope.$root.showMenuIcon = true;
}
});
Is not working! Because it is never called! Maybe $ionicView.beforeEnter does not exist anymore? At least it is never fired.
I solved that problem with this code in each view controller
$scope.$on('$ionicView.beforeEnter', function () {
$ionicSideMenuDelegate.canDragContent(false);
});
$scope.$on('$ionicView.leave', function () {
$ionicSideMenuDelegate.canDragContent(true);
});
Hope it helps
don't forget to add $ionicSideMenuDelegate to your controller

looking for "angular way" of closing open menu when page is clicked

This is what I have, and it works (thankfully, angular supports jQuery out of the box if its loaded)....but I'm wondering what the "angular way" is to accomplish this.
I want to close the open menu if you click anywhere else on the page, but the menu:
<body ng-click="onClickPage($event)">
//app controller:
$scope.onClickPage = function(e){
$log.log(e);
$rootScope.$broadcast('click:page', e);
};
//navbar controller
$rootScope.$on('click:page', function(ev, e){
var $el = $(e.target);
if ( !$el.parents('.menu').length && !$el.hasClass('.menu') ) {
$log.log('hide dropdown');
$scope.hideDropdown();
}
});
That might depend on how your dropdown is implemented but a general idea is to bind/unbind click event handler to the $document when open/close the dropdown.
By doing this way,it doesn't polute global event listeners and $rootScope while the dropdown is not opened.
function onDocumentClicked(e) {
var dropdownEl = angular.element('.dropdown');
if (e && dropdownEl && dropdownEl[0].contains(e.target)) {
return; // do nothing if clicked inside the dropdown
}
closeDropdown();
$scope.$apply();
}
function openDropdown() {
if (!$scope.dropdown.isOpen) {
$scope.dropdown.isOpen = true;
$document.bind('click', onDocumentClicked);
}
}
function closeDropdown() {
if ($scope.dropdown.isOpen) {
$document.unbind('click', onDocumentClicked);
$scope.dropdown.isOpen = false;
}
}
For the full example see: http://plnkr.co/edit/mbx0sLnPetctlWNYdpJC?p=preview

How to cancel routeChange or browser reload when form is incomplete?

There are scenarios like:
Browser reload,
Closing tab
closing browser
Route change (e.g. clicking on links)
Browsers back button was clicked. or history.go(-1). 3 fingers swipe on Macbooks.
that we would want to prevent if the user has filled some sort of form or is in middle of the writing.
I have written this code which works fine but its absolutely not useful if I cant implement it on several textfields. Currently it only check if we are at #/write url. It doesnt check any inputs.
Whats the angular way to deal with this? Whats the best way to check the target textfield. Is a directive the solution?
something like:
<input type="text" warningOnLeave ng-model="title"/>
or
<form warningOnLeave name="myForm">...</form>
$rootScope.$on('$locationChangeStart', function(event, current, previous){
console.log(current);
console.log(previous);
// Prevent route change behaviour
if(previous == 'http://localhost/#/write' && current != previous){
var answer = confirm ("You have not saved your text yet. Are you sure you want to leave?");
if (!answer)
event.preventDefault();
}
});
/**
Prevent browser behaviour
*/
window.onbeforeunload = function (e) {
if(document.URL == 'http://localhost/#/write'){
e = e || window.event;
// For IE and Firefox prior to version 4
if (e) {
e.returnValue = 'You have not saved your text yet.';
}
// For Safari
return 'You have not saved your text yet.';
}
else
return;
}
Forms in Angular have the $dirty/$pristine properties that mark if the user has/hasn't interacted with the form controlls, and the accompanying method $setPristine(). I would base the desired functionality on this feature. Consider:
<form name="theForm" ng-controller="TheCtrl" ...>
This puts the form in the scope of the controller, under the given name. Then something like:
controller("TheCtrl", function($scope, $rootScope) {
$rootScope.$on('$locationChangeStart', function(event, current, previous) {
if( $scope.theForm.$dirty ) {
// here goes the warning logic
}
});
});
Do not forget to call $scope.theForm.$setPristine() where appropriate (i.e. after submitted or cleared).
For the window unload case, you will have to watch the $dirty flag. So in the previous controller:
$scope.$watch("theForm.$dirty", function(newval) {
window.myGlobalDirtyFlag = newval;
});
You have to do this because the window.onbeforeunload event does not have access to the scope of the form. Then, in the global section of your app:
window.onbeforeunload = function (e) {
if( window.myGlobalDirtyFlag === true ) {
// warning logic here
}
};
Again, you may want to clear the global dirty flag when the scope is destroyed, so in the controller:
$scope.$on("$destroy", function() {
window.myGlobalDirtyFlag = false;
});

Resources