ngAnimate doesn't work when modify condition too fast in code - angularjs

I am working on a search page. If no result was returned form server, the no result message box will appear, and if the user still search for that word again, I want the fade out and fade in effect for the message box for user to know the page worked for their search. Everything work fine for this case, since I hide the message box before send the search request to server.
But when I add some validation to the page, the fade out fade in effect doesn't work when I try to hide and show message box for invalid search criteria continuously. At fist I thought I was because I change message state too close in the code. But the problem seems to be different.
When I try to change message from no result to invalid, the effect happens.
It sounds complicated so here is the summary:
Multiple no results messages -> works fine (did call to server)
Multiple invalid search criteria -> doesn't work (no server call)
From no results to invalid search criteria -> works fine (no server call and I don't know why the above doesn't work but this does)
From invalid search criteria to no result -> works fine (no doubts because there is a server call)
I think this might have something to to with the built in $apply function in angular.
Here is the code
var showNoResult = function() {
vm.showSearchResult = false; //result table
vm.showMsg2 = false; //invalid
vm.showMsg1 = true; //no result
vm.showMsg = true; //message box
};
var showInvalid = function() {
vm.showSearchResult = false;
vm.showMsg1 = false;
vm.showMsg2 = true;
vm.showMsg = true;
};
var hideMsg = function() {
vm.showMsg = false;
vm.showMsg1 = false;
vm.showMsg2 = false;
};
vm.sendData = function(page) {
hideMsg();
if(!isFormValid()) {
showInvalid(); //problem here
return;
}
// call to server
mapData(function(data) {
data.pagenum = page || 1;
searchService.searchEmployee(data).then(function(response) {
if (response.data[0] == 0) {
showNoResult();
return;
}
vm.users = response.data[1];
vm.totalItem = response.data[0];
vm.showSearchResult = true;
});
});
};
And this is the html:
<div id="message-box" class="panel panel-default ng-hide" ng-show="searchCtrl.showMsg">
<div class="panel-body">
<i class="fa fa-info" aria-hidden="true" id="no-result-icon"></i>
<p id="no-result-text" ng-show="searchCtrl.showMsg1">
<b>{{ searchCtrl.msg.msg1.msg1_1}}</b>
<br>
{{ searchCtrl.msg.msg1.msg1_2}}
</p>
<p id="invalid-form-text" ng-show="searchCtrl.showMsg2">
{{ searchCtrl.msg.msg2 }}
</p>
</div>
</div>

Related

Angular Material - infinite scroll not working

I'm using Angular Material's infinite scroll, which is defined here: https://material.angularjs.org/latest/demo/virtualRepeat
My first question is: does this virtualRepeat demand to be inside a div with a scrollbar, or can it be applied to the whole page? I actually don't want to have my content inside another div with additional scrollbar (besides the browser's one).
So, I'm using $http and my service returns 30 items if I provide a value of 0, and 60 if I provide value of 1, etc.
var _page = 0;
$scope.infiniteItems = {
numLoaded_: 0,
toLoad_: 0,
// Required.
getItemAtIndex: function(index) {
if (index > this.numLoaded_) {
this.fetchMoreItems_(index);
return null;
}
return index;
},
// Required.
// For infinite scroll behavior, we always return a slightly higher
// number than the previously loaded items.
getLength: function() {
return this.numLoaded_ + 5;
},
fetchMoreItems_: function(index) {
// For demo purposes, we simulate loading more items with a timed
// promise. In real code, this function would likely contain an
// $http request.
if (this.toLoad_ < index) {
this.toLoad_ += 30;
postFactory.getPastPosts(_page).then(angular.bind(this, function(data) {
this.numLoaded_ = this.toLoad_;
_page++;
}));
}
}
};
Here's my HTML
<md-content flex layout-padding>
<div class="virtualRepeatdemoInfiniteScroll">
<md-list>
<md-virtual-repeat-container id="vertical-container">
<div md-virtual-repeat="post in infiniteItems" md-on-demand="" class="repeated-item" flex="">
<md-divider></md-divider>
{{post}}
<past-post model="post" action="reaction(currentPost, candidate, type)"></past-post>
</div>
</md-virtual-repeat-container>
</span>
</md-list>
</div>
</md-content>
The problem is that nothing happens. I get no values. The problem is probably in the postFactory.getPastPosts(_page).then(angular.bind(this, function(data) { as well, since the data is actually in data.data, but there is nothing in the documentation that would show where and how to set the data.
UPDATE
The code for getPastPosts is pretty straightforward: a basic $http request:
function getPastPosts(page) {
return $http.get(baseUrl + '/api/content/past-posts/' + page)
}
I'm using this in various part of the application so there's no doubt that it's working.
You could got an object in getPastPosts() if data returns a value.
The infinite scroll would not be work because it is not an array.
infiniteItems must be type of array.
try like this,
if(data.size == 1){ // I don't know your data structure.
this.push(data.data);
}else{
this = data.data
}

App Fails First Load When Listing Array's Item from a DataSnapshot from Firebase

I am storing a DataSnapshot into a $scope array, so the ng-repeat into HTML div updates my "result list"
The problem is, when I run the code, input a value and click to run the DataSnapshot function, the first result doesn't appear on the app screen, only on the app's log on browser's console. If I run the function again, the result appears. If I change the input and click the button (run the function) again, this input appears in the first try.
So, here's what you will probably need:
Print from first attempt(data appears on console but not on app):
Print from second attempt(data appears twice on console and once on app):
Print from third attempt with another input(data appears once on console and once on app):
Codes:
index.html
<div class="list card">
<div class="item item-body" ng-repeat="locker in lockers">
<a href="#" class="item item-icon-right text-center">
<img ng-src="{{imageSrc}}" style="width: 35px; height: auto;">
<p style="text-align: center">
Locker - {{locker.number}}
<br>
{{key}}
</p>
<i class="icon ion-chevron-right"></i>
</a>
</div>
app.js
angular.module('starter', ['ionic', 'firebase'])
.controller('LockerCtrl', ["$scope", "$firebaseArray", function($scope,$firebaseArray, snapshot){
var lockersRef = new Firebase('https://ifrjarmariosdb.firebaseio.com/armarios');
$scope.getButtonClicked = function() {
var lockernumber = document.getElementById('lockerNumberInput').value;
if(lockernumber.length > 0){
lockerInputedNumber = parseInt(lockernumber);
lockersRef.on('value', function(snapshot){
snapshot.forEach(function(data){
var number = data.val().number;
if(number == lockerInputedNumber){
$scope.key = data.key();
$scope.lockers = [data.val()];
console.log(data.val());
if(number == 101){ -
$scope.imageSrc = "img/locker_test2.png";
}
else{
$scope.imageSrc = "img/locker_test.jpg";
}
}
});
});
}
As you could see by the prints, I'm also facing some trouble to change the image source according to the number value from Firebase. If you could help me to solve that, it would be a great help.
Please, I'm not asking for the solution for this method, if you know a different method to do this, I ask you to post it too.
Thanks!
This code starts loading data from Firebase:
lockersRef.on('value', function(snapshot){
snapshot.forEach(function(data){
var number = data.val().number;
if(number == lockerInputedNumber){
$scope.key = data.key();
$scope.lockers = [data.val()];
console.log(data.val());
if(number == 101){ -
$scope.imageSrc = "img/locker_test2.png";
}
else{
$scope.imageSrc = "img/locker_test.jpg";
}
}
});
The loading happens asynchronously. Since it takes time before the data is available, the browser continues executing the JavaScript after this code.
When the data comes back from the server, it executes your callback function. But at that point, AngularJS is no longer expecting any changes to the $scope.
The solution is to make AngularJS aware of the fact that you've changed the scope. The easiest way to do that, is to wrap the callback into a $timeout() call:
lockersRef.on('value', function(snapshot){
$timeout(function() {
snapshot.forEach(function(data){
var number = data.val().number;
if(number == lockerInputedNumber){
$scope.key = data.key();
$scope.lockers = [data.val()];
console.log(data.val());
if(number == 101){ -
$scope.imageSrc = "img/locker_test2.png";
}
else{
$scope.imageSrc = "img/locker_test.jpg";
}
}
});
});
Some people that ran into the same problem:
Angular JS firebase.(child_added) not rendering on page
ng-show and ng-change unwanted delay
A few other things I note about your code:
you're downloading all lockers and then filtering for the one the user entered client-side. This is wasting bandwidth that your user might be paying for. A better way would be to leave the filtering to Firebase with a Query:
var query = lockersRef.orderByChild('number').equalTo(lockerInputedNumber);
query.on('value', function(snapshot){
there is a binding library for AngularJS+Firebase called AngularFire, which handles the $timeout() thing automatically. It's built on top of Firebase's JavaScript SDK that you're now using, so they interoperate perfectly.

Slow reaction to button click in NgRepeat list of 1000 items

I have a list of 1000+ items which I display using NgRepeat in Angular 1.3. The list populates with buttons. I have noticed significant delay on the click event int he list once it grows in size. When the list is only 5-10 items the clicks are instant. When the list is 1000 there is about 2-5 second delay before the button clicks are actually processed.
Now I cannot tell if this is a browser issue, but I suspect it has to do with too many listeners being used somewhere, causing the browser to check for them.
Here is sample of code in case there is a culprit hiding in there:
<div id="side" class="animated" style="min-height: 250px;"
data-ng-class="{'fadeInRight':documentDone}" data-ng-style="settings.listCss">
<div class="col-md-12 text-center" data-ng-style="settings.listCss"><h4>{{label}}</h4> {{inSide}} </div>
<div data-ng-repeat="doc in ::documents track by $index" id="{{ ::doc.id }}"
class="document ng-hide" data-ng-show="doc.show"
data-ng-init="docSettings = (settingslist[doc.companyid] || settings)" data-ng-style="::docSettings.listCss">
<div class="col-md-12" data-ng-style="docSettings.listCss">
<h4>
<span>{{ ::$index + 1 }}</span>
<span class="title-in-clusters">
{{ ::doc.title }}
<button type="button"
class="btn btn-primary btn-xs"
data-ng-click="viewJob(doc, docSettings)"
data-ng-style="docSettings.buttonCss">
<strong>VIEW</strong>
</button>
<a href="{{ ::doc.joburl }}" class="apply" target="_blank">
<button type="button" class="btn btn-primary btn-xs" data-ng-click="apply(doc.jobid, doc.companyid)"
data-ng-style="docSettings.buttonCss">
<strong>APPLY</strong>
</button>
</a>
</span>
</h4>
</div>
<div class="col-md-12" data-ng-style="docSettings.listCss">
<span class=""><strong>ID: </strong>{{ ::doc.jobid }}</span>
<img data-ng-if="docSettings.heading.logourl && docSettings.heading.logourl != ''"
data-ng-src="{{docSettings.heading.logourl}}" class="side-logo inline-block" id="">
</div>
<div class="col-md-12" data-ng-style="docSettings.listCss">
<strong>Location: </strong><span class="">{{ ::doc.location }}</span>
</div>
<div class="col-md-12" data-ng-style="docSettings.listCss">
<strong>Updated Date: </strong><span class="">{{ ::doc.updateddate }}</span>
</div>
<div class="col-md-12" data-ng-style="docSettings.listCss">
<hr data-ng-style="docSettings.listCss">
</div>
</div>
</div>
There is nothing offensive about the other functions that are called when the button is pressed.
var modalInstance;
$scope.viewJob = function(modalDoc, docSettings) {
$scope.modalDoc = modalDoc;
$scope.docSettings = docSettings;
//the trusAsHtml takes string creates an object, so this will in essence convert string to object
//make sure you check if it is a string since it could be called multiple times by user (close and reopen same modal)
if (modalDoc.overview && typeof modalDoc.overview === 'string') {
$scope.modalDoc.overview = $sce.trustAsHtml(modalDoc.overview);
}
if (modalDoc.qualifications && typeof modalDoc.qualifications === 'string') {
$scope.modalDoc.qualifications = $sce.trustAsHtml(modalDoc.qualifications);
}
if (modalDoc.responsibilities && typeof modalDoc.responsibilities === 'string') {
$scope.modalDoc.responsibilities = $sce.trustAsHtml(modalDoc.responsibilities);
}
modalInstance = $modal.open({
templateUrl: 'app/modal/job_preview.html',
//templateUrl: 'myModalContent.html',
scope: $scope
});
};
I want to optimize this code so it can sever a list of up to 1500, but I cannot for the life of me find the culprit.
I will also take any solutions to reduce the load instead. Like for now I am thinking I may limit the number of DOM elements to 10 to so, and have angular rotate what is being viewed as user scrolls if it will result in better UX.
UPDATE:
Many things have been tried, from use of bind-once to more convoluted solutions that retard some of the watchers Which are enat but require a lot of Math to estimate which items are visible etc.
I finally decided on one solution that was easiest to do: I made a list of only items I wish shown and on mouse scroll up or down I edit the list.
First part of the solution is use of two directives:
.directive('ngMouseWheelUp', function() {
return function($scope, $element, $attrs) {
$element.bind("DOMMouseScroll mousewheel onmousewheel",
function(event) {
// cross-browser wheel delta
var event = window.event || event; // old IE support
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
if(delta > 0) {
$scope.$apply(function(){
$scope.$eval($attrs.ngMouseWheelUp);
});
// for IE
event.returnValue = false;
// for Chrome and Firefox
if(event.preventDefault) {
event.preventDefault();
}
}
});
};
})
.directive('ngMouseWheelDown', function() {
return function($scope, $element, $attrs) {
$element.bind("DOMMouseScroll mousewheel onmousewheel", function(event) {
// cross-browser wheel delta
var event = window.event || event; // old IE support
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
//console.log(event);
if(delta < 0) {
$scope.$apply(function(){
$scope.$eval($attrs.ngMouseWheelDown);
});
// for IE
event.returnValue = false;
// for Chrome and Firefox
if(event.preventDefault) {
event.preventDefault();
}
}
});
};
})
These two enable me to disable scrolling in the list on the right side. Then I would create two additional arrays from the documents in routeScope. First list would be generated whenever the documents were updated (which was an event listener for event emitted by the UI of the right hand side graph), this filter would only return array members that had the show property set to true:
var showFilter = function(object) {
return object.show;
}
This would be my array of visible items. From this array I created another Array of shown items. I defined a constant for max size of 7, so at most there are 7 items shown. And of course I set overflow of the parent container to none to disable scrollbar. (I may add a scroll graphic so the user knows he can scroll this field later)
Then I added the following directives to the side div:
data-ng-mouse-wheel-up="listUp()" data-ng-mouse-wheel-down="listDown()"
And inside the controller I defined listUp and listDown to work off an index and the max size constant to figure out which elements from the visible list I should add to the front or the back of the shown list.
/**
* Simulate scrolling up of list by removing bottom element and adding to top
*/
$scope.listUp = function() {
$rootScope.shownDocuments.unshift(getPrev());
$rootScope.shownDocuments.pop();
}
/**
* Simulate scrolling down of list by removing top element and adding to bottom
*/
$scope.listDown = function() {
$rootScope.shownDocuments.push(getNext());
$rootScope.shownDocuments.shift();
}
/**
* return next item in visibleDocuments array
*/
var getNext = function() {
$rootScope.topIndex++;
if ($rootScope.topIndex > $rootScope.visibleDocuments.length) {
$rootScope.topIndex -= $rootScope.visibleDocuments.length;
}
return ($rootScope.visibleDocuments[($rootScope.topIndex+max_shown_size)%$rootScope.visibleDocuments.length]);
}
/**
* Return previous item in visibleDocuments array
*/
var getPrev = function() {
$rootScope.topIndex--;
if ($rootScope.topIndex < 0) {
$rootScope.topIndex += $rootScope.visibleDocuments.length;
}
return ($rootScope.visibleDocuments[$scope.topIndex]);
}
Use of rootScope vs scope is mostly because modals would cause some undesirable behaviors if they were dismissed improperly.
Finally a reset function for the view:
/**
* Resets the list of documents in the visibleList (IE which are visible to client)
*/
var updateVisibleDocuments = function() {
$rootScope.topIndex = 0;
$rootScope.visibleDocuments = $rootScope.documents.filter(showFilter);
//clear view
$rootScope.shownDocuments = [];
$rootScope.topIndex = 0;
for (var i = 0; i < max_shown_size; i++) {
$rootScope.shownDocuments.push(getNext());
}
$rootScope.topIndex = 0;
}
This solution works really well because I only render 7 items even if my list has 100k items. This limits number of watchers tremendously.
You may want to try paginating to reduce the amount of things angular and the browser need to deal with on screen at any one time.

How can I get ng-click to function with ng-repeat and ng-bind-html?

I am trying to get a ng-click directive to function within an ng-repeat and ng-bind-html. The ng-click code is added to a string of html from data pulled from the server (hence the ng-bind-html). The setup has a controller, a base template that is put onto the page with Drupal, and a partial that is loaded via the template from Drupal.
The controller looks like this at the moment:
var guideListController = angular.module('app')
.controller('guideListController', [
'$scope',
'$sce',
'$compile',
'ViewService',
'ToolKit',
function($scope, $sce, $compile, ViewService, ToolKit) {
// Storage for which rows need more/less links
this.rowIndex = [];
this.showFull = false;
this.showFullClick = function() {
alert('Showfull');
};
this.trustIntro = function(code) {
return $sce.trustAsHtml(code);
};
// Fetch the guide list view from services
var data = ViewService.get({view_endpoint:'guide-service', view_path: 'guide-list'}, function(data) {
//console.log(data);
// Update/process results
for (var row in data.results) {
// Create short intro w/ truncate.js
data.results[row].Intro_short = $sce.trustAsHtml($scope.guideList.getShortIntro(data.results[row], row));
//data.results[row].Intro_short = $scope.guideList.getShortIntro(data.results[row], row);
// Update intro
data.results[row].Introduction = $sce.trustAsHtml($scope.guideList.updateIntro(data.results[row], row));
//data.results[row].Introduction = $scope.guideList.updateIntro(data.results[row], row);
}
$scope.guideList.guides = data.results;
});
// Add a read less anchor tag at the end of the main intro
this.updateIntro = function(row, row_index) {
var intro = row['Introduction'].trim();
if ($scope.guideList.rowIndex[row_index]) { // only apply Less link if needed
var index = intro.length - 1;
var tag = [];
if (intro.charAt(index) === '>') { // we have a tag at the end
index--;
do {
tag.push(intro.charAt(index));
index--;
} while (intro.charAt(index) != '/'); // the closing tag
index--; // we move the index one more for the "<"
tag.reverse(); // Reverse
tag = tag.join('');
}
var inserts = ['div', 'p']; // we insert the Less link here.
if (jQuery.inArray(tag, inserts) >= 0) { // insert into the tag
intro = intro.substr(0, index) + ' <a class="less" ng-click="$parent.guideList.showFull = false">Less</a>' + intro.substr(index);
}
else { // insert at the end of the html
intro = intro + '<a class="less" ng-click="this.showFull = false">Less</a>';
}
}
return intro;
};
// Truncate the long intro into a shorter length blurb
this.getShortIntro = function(row, row_index) {
// Truncate if necc.
var short_intro = jQuery.truncate(row['Introduction'], {
length: 250,
words: true,
ellipsis: '\u2026 <a class="more moreish" attr-ng-click="guideList.showFullClick()">Read on</a>'
});
var more = jQuery('.more', short_intro); // select more link
if (more.length) { // do we have a more link
$scope.guideList.rowIndex[row_index] = true;
}
else { // no more link
$scope.guideList.rowIndex[row_index] = false;
}
$compile(short_intro)($scope);
return short_intro;
};
}]);
As you can see in the ViewService.get() call, data is fetched and then processed. The processing simply involves putting a link at the end of the "Intro" field that is intended to be clickable.
For a while I was having a tough time to even get the ng-click directive to even show (it was being filtered out w/out $sce.trustAsHtml). Now it is there but clicking it has no effect.
The main template (from Drupal) currently looks like:
<div class="guide-listing" ng-controller="guideListController as guideList">
<a ng-click="guideList.showFullClick()">Click me</a>
<div class="guide-teaser"
ng-repeat="guide in guideList.guides"
ng-include src="'/sites/all/themes/ngTheme/ngApp/partials/guide_teaser.html'">
<!-- See guide_teaser.html partial for guide teasers -->
</div>
</div>
The ng-click as placed in the Drupal template above works as expected.
And for the partial that is used in the ng-repeat, it looks like so:
<div ng-controller="guideListController as guideList">
<h2 class="guide-teaser-title">{{guide.node_title}}</h2>
<div class="guide-teaser-intro" ng-bind-html="guide.Introduction" ng-show="guide.showFull">
{{guide.Introduction}}
</div>
<div class="guide-teaser-intro-short" ng-bind-html="guide.Intro_short" ng-show="!guide.showFull">
{{guide.Intro_short}}
</div>
</div>
So far I have only been working on getting the ng-click to work on the short_intro and have had no success so far. Any ideas as to what I am doing wrong would be greatly appreciated!
Ok, So I did get some traction! I used the ngHtmlCompile (http://ngmodules.org/modules/ng-html-compile) directive that was created by https://github.com/francisbouvier (thanks!)
The issue was that the new (dynamic) html wasn't being compiled.
At first it didn't work. I had two issues that prevented it from firing:
A: I stopped using $sce.trustAsHtml. Using this in conjunction with the directive caused the content to disappear!
B: The other issue was one of scope. After I changed the directive such that transclude was set to false it worked just fine!

Execute different Event on First and second click angular js

I have a situation where i need to execute different event on first and second click on div.
On first click div will be expanded and in second click it will be redirected to it's detail page. Div contains details of post.
<div ng-click="select(comment._id);"
ng-dblclick="changeurl(user.username,data.type,comment._id)"
enter ng-repeat="user in data.user">
Till now i was expanding div on first click and then on double click i was redirecting it to it's detail page.
what would be the best way to do it.
right now my idea is to make a counter on ng-click and then execute event.
can we execute it on the DOM End.
<div ng-click="counter = counter + 1" ng-repeat="user in data.user" ng-init="counter = 0" >
is there any other directive where i can execute select(comment._id) changeurl(user.username,data.type,comment._id) conditionally or how can i call these functions conditionally ?
Update: on Diana advice here is updated status:
Here i have no of div's coming from ng-repeat, here i have two type of layouts which are displayed according to data.
<div ng-repeat="data in comments">
<div ng-if="data.type=story">
<div ng-click="clickEvent($index,comment._id, user.username,data.type);" enter ng-repeat="user in data.user">
//displaying data here
</div>
</div>
<div ng-if="data.type=news">
<div ng-click="clickEvent($index,comment._id, user.username,data.type);" enter ng-repeat="user in data.user">
//displaying data here
</div>
</div>
</div>
$scope.secondClick = [];
//scope data
myservice.data().then(function(response){
$scope.comments = response.data;
for (i=0; i< $scope.comments.length;i++){
$scope.secondClick[i] = false;
}
});
$scope.clickEvent = function(index,id, userName, type){
if(!$scope.secondClick[index]){
// Execute first-click logic (call select function with the id).
$scope.secondClick[index] = true;
}
else{
// Execute second-click logic (call changeurl function with the id, userName, and type).
}
}
I tried providing index to function and manipulate them. Because of nested ng-repeat i am getting index '0'. .
UPDATE2:
I tried to understand your setup from the question and came up with a full working demo accordingly. I hope this works for your case!
http://plnkr.co/edit/ARsDpRH7orzZQLU1pin1
Please let me know how this goes.
/////////////////////////////////////
You could have some boolean variable that is initially set to false, say $scope.secondClick - when you click the button the first time set it to true. When clicking it the next time the variable is true so you execute the "second click" logic.
Something like:
<div ng-click="clickEvent(comment._id, user.username,data.type);" enter ng-repeat="user in data.user">
In your controller, define:
$scope.secondClick = false;
$scope.clickEvent = function(id, userName, type){
if(!$scope.secondClick){
// Execute first-click logic (call select function with the id).
$scope.secondClick = true;
}
else{
// Execute second-click logic (call changeurl function with the id, userName, and type).
}
}
UPDATE:
Given that you have more than one div, we can tweak the solution a bit by having an array of boolean values in the scope and passing the index to know which is which:
<div ng-click="clickEvent($index, comment._id, user.username,data.type);" enter ng-repeat="user in data.user">
In the controller:
$scope.secondClicks = [];
//Initialize all values to false, based on the number of divs.
for(var i = 0; i<NoOfDivs; i++){
$scope.secondClicks[i] = false;
}
$scope.clickEvent = function(index, id, userName, type){
if(!$scope.secondClicks[index]){
// Execute first-click logic (call select function with the id).
$scope.secondClicks[index] = true;
}
else{
// Execute second-click logic (call changeurl function with the id, userName, and type).
}
}
Let us know if this works please. If someone has a neater solution, I'd like to check it out as well :)
I think this may be a simple way to tell JavaScript to do different things depending on the number of clicks. This example shows swapping of two different events. Basicly, I just limited the counting from 0 to 1 and made sequence circular. Ofc, you can make more than just two. I think the advantige of this is that is circular, so the user may navigate freely (first he expands something, than he shrinks it back, than he expands it again etc...). Maybe by following this principle you will solve your code.
<!DOCTYPE html>
<head>
<style>
#division {background-color: red;color: white;width: 10%;height: 20%;position: fixed;top: 10%;left: 10%;-webkit-transition: 1s;-moz-transition: 1s;-ms-transition: 1s;-o-transition: 1s;transition: 1s;}
#division:hover {background-color: blue;cursor: pointer;}
</style>
</head>
<body>
<script type="text/javascript">
var clicks = 0;
function onClick() {
clicks += 1;
if (clicks != 1) {
clicks = 0;
};
if (clicks == 1) {
document.getElementById("division").style.left = 30+'%';
}else {
document.getElementById("division").style.left = '10%';
};
};
</script>
<div onClick="onClick()"><a id="division">Click me Twice!</a></div>
</body>
</html>
I did this by putting post id in cookie. On first click that post's id is stored in cookie and if user click again it is founded in cookie store second click action is triggered. Hence we do action on first and second click.
$scope.clickEvent = function(id,name,type){
var favoriteCookie = $cookieStore.get('divonclick');
$cookieStore.put('divonclick',id);
if(favoriteCookie == id){
//second click action
}else{
//first click action
}
}
Try This:
In html div:
ng-init="count=0"
ng-click="select(count)(count=count+1);"
In JS:
$scope.select = function(count) {
if(count%2 == 0 ) {
here write your SECOND click functionality.
} else {
here write your FIRST click functionality.
}
}

Resources