how to create up/down voting function in angularjs - javascript

Hey guys may i know how can i create a up/down voting function in angularjs ? i want to make it to something similar to stackoverflow or reddit.
i found a Jquery plugin https://github.com/janosgyerik/jquery-upvote that does what i want but its in Jquery.
i have tried several approach to do it but i still can't get it works well. here's my approach.
HTML
<a class="green" ng-click="isUpVoted = !isUpVoted" ng-style="afterVoteUp" href=""> <i title="Up Votes" class="fa fa-arrow-circle-up fa-2x"></i></a>
<a class="maroon" ng-click="isDownVoted = !isDownVoted" ng-style="afterVoteDown" href="" > <i title="Down Votes" class="fa fa-arrow-circle-down fa-2x "></i></a>
Controller
$scope.isUpVoted = false;
$scope.$watch("isUpVoted",function(newVal, oldVal){
if(newVal != oldVal){
if(newVal){
// first click
// upvote
}else{
// second click
// remove upvote
}
}
});
$scope.isDownVoted = false;
$scope.$watch("isDownVoted",function(newVal, oldVal){
if(newVal != oldVal){
if(newVal){
// first click
// downvote
}else{
// second click
// remove downvote
}
}
});
which work completely fine for one button, however i still can't figure out how to make this 2 buttons work together, for example when user click upvote downvote will cancel or vice versa and click the upvote again to cancel vote.

Just use a single scope variable to act like a toggle button.
Sample Demo: http://plnkr.co/edit/C4w9hDK3xW1R0ua3WPgU?p=preview
HTML:
<body ng-controller="MainCtrl">
<i title="Up Votes" ng-click="changeVote(vote, 'up')" class="fa fa-arrow-circle-up fa-2x" ng-class="{true:'up', false:''}[vote=='up']"></i>
<br>
<i title="Down Votes" ng-click="changeVote(vote, 'down')" class="fa fa-arrow-circle-down fa-2x" ng-class="{true:'down', false:''}[vote=='down']"></i>
<br>Vote: {{vote}}
Controller Logic:
app.controller('MainCtrl', function($scope) {
$scope.changeVote = function(vote, flag) {
$scope.vote = vote == flag ? 'None' : flag;
alert($scope.vote);
};
});

It should be simple to make something like this.
Here's a simple example:
JS:
var app = angular.module('voteApp', []);
app.controller('MainCtrl', function ($scope) {
$scope.upVote = function () {
$scope.vote++;
}
$scope.downVote = function () {
$scope.vote--;
}
$scope.vote = 0;
});
Fiddle.

Related

toggle switch ngclass onclick with angularjs

I want to change the class of a button when it clicked and also reverse back to its former state when its click again
$scope.like_btn = "icon ion-ios-heart";
$scope.like_btn2 = "icon ion-ios-heart assertive";
$scope.likepic=function() {
event.preventDefault();
if ($scope.like_btn === "icon ion-ios-heart"){
$scope.like_btn = "icon ion-ios-heart assertive";
$http.post("http://localhost/mywork/scripts/like.php",
{'u_pic_id':$scope.u_pic_id})
.success(function(data){
console.log(data)
});
}
else {
$scope.like_btn = "icon ion-ios-heart assertive";
$scope.like_btn = "icon ion-ios-heart";
$http.post("http://localhost/mywork/scripts/like_delete.php",
{'u_pic_id':$scope.u_pic_id})
.success(function(data){
console.log(data)
});
}
}
HTML
Click to like
<i ng-class="{ '{{like_btn}}': item.answer==='no liked','{{like_btn2}}':item.answer=='liked' }" ></i> {{item.love_total}} Likes
Your 'item' is probably not getting updated after the service succeeded.
So one way is to add following to the controller:
$scope.item.isLiked = false; // or initiase it with item.isLiked
$scope.likepic=function(item) {
item.isLiked = item.isLiked;
...
...
}
Change your angular expression to the following :
<i ng-click="likepic(item)" ng-class="{ '{{like_btn}}': item.answer=='no liked','{{like_btn2}}': item.answer=='liked' }" ></i>
You need to update the varible names little bit.
As I look at your case, the only change with onclick is that you are adding 'assertive' class. Below would be the approach.
Changes in the HTML View:
Click to like
<i class="icon ion-ios-heart" ng-class="{'assertive': liked}" ></i> {{item.love_total}} Likes
Changes in Javascript
// Initialize the flag here
$scope.liked = false;
$scope.likepic = function() {
event.preventDefault();
// Toggle the flag here
$scope.liked = !$scope.liked;
// Then perform task as per the new value
// There is some possibility of optimization below too. But since that is not the question, no changes are done here
if ($scope.liked) {
$http.post("http://localhost/mywork/scripts/like.php", { 'u_pic_id': $scope.u_pic_id })
.success(function(data) {
console.log(data)
});
} else {
$http.post("http://localhost/mywork/scripts/like_delete.php", { 'u_pic_id': $scope.u_pic_id })
.success(function(data) {
console.log(data)
});
}
}

when location path is empty use onClick function

I'm trying to use a href and onClick depending on the url.
if $location.path() is empty such like www.mysite.com/ then use onClick function
if url is like www.mysite.com/about then use href="javascript:history.back()"
<a href="javascript:history.back()" data-ng-click="vm.backToResult();">
<i class="fa fa-angle-left"></i>
Back to Search Results
</a>
vm.backToResult = function() {
if (!$location.path()) {
$window.history.back();
} else {
$window.location.href = '#!/list-of/options/';
}
}
I think this is working but I have to double click to actually trigger it but not entirely sure to be honest.

Can't trigger action after changing element's ID

I have a show/hide password button, when I click to SHOW the password, it works, but when I try to hide it again it doesn't.
Fiddle: http://jsfiddle.net/vcvgj09z/
<input type="password" id="pass1" value="Now try to hide me">
<i class="fa fa-eye"></i> Show
$("#show-password").on("click",function() {
$(this).html('<i class="fa fa-eye-slash"></i> Hide');
$(this).prop("id","hide-password");
$("#pass1").attr("type","text");
});
$("#hide-password").on("click",function() {
$(this).html('<i class="fa fa-eye"></i> Show');
$(this).prop("id","show-password");
$("#pass1").attr("type","password");
});
As per my comment, the reason why your code is not working is because the element #hide-password is not present in the DOM at runtime, so no click events will be bound to it.
Although you can use .on() to listen to event bubbling, I strongly advise against changing IDs of elements. Instead, you can store the toggle on/off state as a jQuery data object. The advantages of this method is that:
does not rely on changing the markup and event bubbling
stores the toggle state of the password by evaluating and modifying the jQuery data object
allows other elements to manipulate/influence the toggle state
See fiddle here: http://jsfiddle.net/teddyrised/vcvgj09z/10/
$('#toggle-password').click(function() {
// Check state
if(!$(this).data('state') || $(this).data('state') == 0) {
// If the data object "state" is undefined or have a value of 0, convert password to text
// Update HTML and data object
$(this)
.html('<i class="fa fa-eye-slash"></i> Hide')
.data('state', 1);
// Change password to text
$("#pass1").attr('type', 'text');
} else {
// If the data object "state" has a value of 1, convert text to password
// Update HTML and data object
$(this)
.html('<i class="fa fa-eye"></i> Show')
.data('state', 0);
// Change text to password
$("#pass1").attr("type","password");
}
});
Try something like this ...
$("body").on("click", "#show-password", function() {
... and associated ...
$("body").on("click", "#hide-password", function() {
This way when the ID dynamically changes, the on-click's will work.
Your code doesnt work because it does not support the dynamically setted elements.
The correct way to set the events for dynamically added elements is by using $(document).on().
JS:
$(document).on("click", "#show-password", function() {
$(this).html('<i class="fa fa-eye-slash"></i> Hide');
$(this).prop("id","hide-password");
$("#pass1").attr("type","text");
});
$(document).on("click", "#hide-password", function() {
$(this).html('<i class="fa fa-eye"></i> Show');
$(this).prop("id","show-password");
$("#pass1").attr("type","password");
});
Updated jsFiddle
You should use delegate. Because you generated new DOM
$(document).on("click","#show-password",function() {
//....
});
$(document).on("click","#hide-password",function() {
//....
});

jQuery .click() doesn't fire but console.log shows output

I'm having a problem in my code where I click a DOM-element using JavaScript. The click does not work and I am almost sure it is no dumb programming mistake (always dangerous to say).
After deleting some DOM-elements I want my code to click an element and trigger its onclick event. However this doesn't work. According to my code the event triggers but the event doesn't happen and the click event returns the jQuery object.
HTML:
<div class="castor-tabs">
<div class="castor-tab" data-path="../SiteBuilding/alertbox.js" data-saved="saved" data-editor="5475c897f1900editor">
<span class="castor-filename">alertbox.js</span>
<span class="castor-close"><i class="fa fa-fw fa-times"></i></span>
</div>
<div class="castor-tab" data-path="../SiteBuilding/index.php" data-saved="saved" data-editor="5475c89903e70editor">
<span class="castor-filename">index.php</span>
<span class="castor-close"><i class="fa fa-fw fa-times"></i></span>
</div>
<div class="castor-tab active" data-path="../SiteBuilding/makesite.php" data-saved="saved" data-editor="5475c8997ac77editor">
<span class="castor-filename">makesite.php</span>
<span class="castor-close"><i class="fa fa-fw fa-times"></i></span>
</div>
</div>
JavaScript:
$(".castor-tabs").on("click", ".castor-close", function() {
var tab = $(this).parent();
if(tab.attr("data-saved") == "saved") {
// File is saved
if($(".castor-tab").length > 1) {
// 1 element is 'tab' the other is a second tab
if(tab.next().length > 0) {
// If element is to the right
window.newTab = tab.next();
} else if(tab.prev().length > 0) {
// If element is to the left
window.newTab = tab.prev();
}
} else {
window.newTab = false;
}
var editor = tab.attr("data-editor");
$("#" + editor).remove(); // textarea linked to CodeMirror
$("#" + editor + "editor").remove(); // Huge CodeMirror-element
tab.remove();
if(window.newTab) {
console.log("window.newTab.click()");
console.log(window.newTab.click()); // Simulate click()
}
} else {
// File isn't saved
}
});
The onclick event:
$(".castor-tabs").on("click", ".castor-tab", function() {
$(".castor-tab.active").removeClass("active");
$(this).addClass("active");
var editor = $(this).attr("data-editor");
$(".CodeMirror").hide();
$("#" + editor).show();
});
I saved the element in the window object for a reason. After the code runs and it skips the click-part I still have the DOM-element i want to click saved in the window object. This means I can run
console.log(window.newTab.click());
again. Surprisingly this does click the element and this does activate the click-event. It also returns the DOM-element instead of the jQuery-object.
The image shows in the first two lines the failed click. The third line is my manual input and the fourth line is the successful return value of the click().
I hope you can help me to solve this.
UPDATE
.trigger("click") unfortunately gives the same output..
UPDATE 2
To help you i made the website available on a subdomain. I know many of you hate it if you have to go to a different page but I hope you'll forgive me because in my opinion this cant be solved through JSFiddle.
The link is http://castor.marknijboer.nl.
After clicking some pages to open try closing them and you'll see what i mean.
try adding return false; at the end, when binding .castor-close click event
$(".castor-tabs").on("click", ".castor-close", function() {
var tab = $(this).parent();
if(tab.attr("data-saved") == "saved") {
// File is saved
if($(".castor-tab").length > 1) {
// 1 element is 'tab' the other is a second tab
if(tab.next().length > 0) {
// If element is to the right
window.newTab = tab.next();
} else if(tab.prev().length > 0) {
// If element is to the left
window.newTab = tab.prev();
}
} else {
window.newTab = false;
}
var editor = tab.attr("data-editor");
$("#" + editor).remove(); // textarea linked to CodeMirror
$("#" + editor + "editor").remove(); // Huge CodeMirror-element
tab.remove();
if(window.newTab) {
console.log("window.newTab.click()");
console.log(window.newTab.click()); // Simulate click()
}
} else {
// File isn't saved
}
return false;
});
Instead of simulating a click, why not just pull the click logic out of your click function and just call the javascript function using the arguments that you'll need to perform your business logic?
Your code is working but not able to trigger click event binded to castor-close because i tag is empty. Put some text in it and check
<span class="castor-close"><i class="fa fa-fw fa-times">Click me</i></span>
DEMO
Your click handler has the requirement that the click target should have the class castor-close but when you are calling click via JavaScript you are clicking the parent element instead (.castor-tab), and the click handler doesn't react.

Click issue if button has childs

I've:
backdrop = document.getElementById('backdrop');
dialog = document.getElementById('dialog');
dialog_body = document.querySelector('#dialog .body');
document.addEventListener('click', function(e) {
if ( matches.call(e.target, '[data-show=dialog]')) {
buoy.addClass(backdrop, 'fadeIn');
buoy.addClass(dialog, 'fadeIn');
var href = e.target.parentNode.getAttribute('action');
dialog_body.innerHTML = '<div>FOOOOO</div>';
[].forEach.call(document.querySelectorAll('[data-hide=dialog]'), function(el) {
el.addEventListener('click', function() {
buoy.removeClass(backdrop, 'fadeIn');
buoy.removeClass(dialog, 'fadeIn');
})
})
}
}, false);
and [data-show=dialog] is:
<button type="sumit" class="btn xs default" data-show="dialog">
<i class="ellipsis-v"></i>
</button>
If I click on
<i class="ellipsis-v"></i>
the code doesn't work..
If I click out of
<i class="ellipsis-v"></i>
the code works perfectly..
Also if I have:
<button type="sumit" class="btn xs default" data-show="dialog">
<i class="ellipsis-v"></i>
<span>fooo</span>
</button>
If I click on
<i class="ellipsis-v"></i>
or
<span>fooo</span>
the code doesn't work..
If I click out of
<i class="ellipsis-v"></i>
or
span>fooo</span>
the code works perfectly..
What is the problem?
Why Not:
function handler(e){
var t=e.target;
if(t.dataset['show']=='dialog'||t.parentNode.dataset['show']=='dialog'){
/* code ...... */
}
}
document.addEventListener('click',handler,false);
in this case you have one eventHandler.(no loops).
you can add that handler to the parentNode for simplicity.
and you have to add a better check for t.dataset['show']=='dialog' as it produces an error if it has no dataset. (i wrote it just to give you an idea)
btw you search for data-hide but you have only data-show
if you have any questions just ask..
if i misunderstood your question tell me so i can reelaborate the code.
DEMO
http://jsfiddle.net/A7xk2/1/
Less eventHadlers is always more performance...
also in this example i'm just writing now... i need alot of mouse events and most of them are on the document itself...
http://jsfiddle.net/LxX34/12/
EDIT
Add the click handler on the btn elements
it works on span on li and on button as you can see in this example.
maybe your li has some sort of preventDefault or return false??
http://jsfiddle.net/A7xk2/2/

Categories

Resources