hello guys i'm trying to implement Upvote feature but i'm having some difficulties to get it toggle, by toggle i mean when user click the button/link it will perform upvote if the user click it again it will remove the upvote, just like a toggle button but i can't seem to find any relevant info from google. this is what i have so far
UPDATED
$scope.up = function(){
if(s_session != null){ // check user is logged in or not
data.getUserData().success(function(userData){ // get user data
$scope.a = data1.votes.up; // this is the data from database
// is a list of username that who voted this post
$scope.b = userData.publicUsername.display;// this is the current username
if($scope.a.indexOf($scope.b) == -1){ //check this username whether is in
// the list if -1 mean not
$scope.user ={};
$scope.user = userData;
$scope.user.permalink = $routeParams.permalink;
$http.post('/contentHandler/post/vote/up',$scope.user). // perform upvote
success(function(updatedData) {
$scope.votedMsg="VOTED";
$scope.afterVoteUp={'color':'#B3B3B3'}
}).error(function(err){
});
}else{ //else remove upvote
$scope.user ={};
$scope.user = userData;
$scope.user.permalink = $routeParams.permalink;
$scope.votedMsg="";
$scope.afterVoteUp={'color':'#2ecc71'}
$http.post('/contentHandler/post/vote/up/remove',$scope.user).
success(function(Data) {
}).error(function(err){
});
}
});
}else{
$location.path('/login'); //redirect to login if not logged in
}
}
but problem is i can't click the button twice, the first click will perform upvote but the second click still will perform upvote, the problem is because the list of username is not being updated, but if i refresh the page and click it again it will remove the upvote. may i is there any better way to do this ?
A simple approach would be to maintain the state in a variable, but please read below for caveats
$scope.upVoted = false
$scope.up = function() { //ng-click
if ($scope.upVoted) {
$http.post('/contentHandler/post/vote/up', $scope.user).
success(function(updatedData) {
$scope.votedMsg = "VOTED";
$scope.afterVoteUp = {
'color': '#B3B3B3'
}
}).error(function(err) {
});
}else{
$http.post('/contentHandler/post/vote/up/remove', $scope.user).
success(function(updatedData) {
$scope.votedMsg = "VOTE REMOVED";
$scope.afterVoteUp = {
'color': '#FFFFFF'
}
}).error(function(err) {
});
}
});
The potential issue you have with this and all frontend approaches is that the user can trivially change the value of upVoted, and vote again.
Assuming you're doing some validation in /contentHandler/post/vote/up you could alter it to toggle the vote on the server. That way the response could be the updated voted status from the server.
If you manage the state on the frontend, how will you know if the user has voted when they refresh the page?
A clean approach would be:
<div ng-click="isUpVoted = !isUpVoted">{{isUpVoted}}</div>
JS:
$scope.isUpVoted = false;
$scope.$watch("isUpVoted",function(newVal, oldVal){
if(newVal != oldVal){
if(newVal){
// perform upvote
}
else{
// perform remove upvote
}
}
});
Fiddle
I don't know AngularJS, but basic programming knowledge and assuming .up is the click handler tells me you need:
$scope.up = function() {
if( {ALREADY_UP_VOTED} ) {
//perform remove upvote
} else {
//perform upvote
}
}
EDIT: (with dfsq's comment in mind)
I guess you could look at your $scope.votedMsg variable:
$scope.up = function() {
if( $scope.votedMsg == "VOTED" ) {
// perform remove upvote
// remove upvote thing..
$scope.votedMsg = "";
} else {
//perform upvote
}
}
Related
I'm trying to make comment system, the issue that the comment didn't show up , and if it did then the vote and username and other items didn't show up
The vote button is working
I don't what is the issue here?
https://codepen.io/MRuhaily/pen/OoNRQp
HTML
JQuery
$(document).ready(function() {
$('.upvote').on('click', function() {
$(this).on('click', function() {
var counter = 0;
counter = counter + 1;
$('.votes').html(counter);
});
});
$('.downvote').on('click', function() {
$(this).on('click', function() {
var counter = 0;
counter = counter - 1;
$('.votes').html(counter);
});
});
$('#addCommentButtton').on('click', function(e) {
var comment = $('#commentText').val();
$('<li>').text(comment).prependTo('.Comments');
$('#commentDiv').val('');
if (comment.length > 1) {
$('#addCommentButtton[type="submit"]').removeClass('disabled');
} else if (comment.length === 0) {
$('#addCommentButtton[type="submit"]').addClass('disabled');
}
});
});
The button type is submit so the default behaviour is to submit the form.
You have to add e.preventDefault() to the callback function:
$('#addCommentButtton').on('click',function(e){
e.preventDefault();
// rest of the code
})
That way the form will not be submitted, and the page won't be reloaded. Beside that the textarea has the id commentDiv and not commentText so it has to be:
var comment = $('#commentDiv').val();
The voting is also broken, but as you say it works like you want and your question is about the comment I won't target that problem. And it is also mentioned in the comment what you did wrong with the voting.
I am trying to execute some code that has a callback when clicking on specific links. The callback is to click the link again, but on the second pass, the method returns true to follow normal behavior. But for some reason, it's not working? I use clickedLink for proper scope. In the event callback, this was referring to window.
UPDATE
For a little more clarity, I agree normally this wouldn't be an optimal solution, but I am using Google's Tag Manager to monitor eCommerce traffic. I am trying to make sure product clicks get pushed to their dataLayer, and using their event callback to resume normal behavior. More info here: https://developers.google.com/tag-manager/enhanced-ecommerce#product-clicks
This is my updated method based on the answers below, but it still doesn't work.
var shopCartBtnClicked = false;
var clickedLink;
jQuery('#pdp_add_cart, .add_to_cart_button').click(function(e) {
if (shopCartBtnClicked === true) {
shopCartBtnClicked = false; //I make it here just fine
} else {
e.preventDefault();
clickedLink = this;
var pdp = false;
if (mmProduct) {
//On detail page
mmProduct.qty = jQuery('input[name="quantity"]').val();
pdp = true;
} else {
//on a shopping page
mmProduct = findProductClicked(this);
mmProduct.qty = 1;
}
dataLayer.push({
'event': 'addToCart',
'ecommerce': {
'currencyCode': 'USD',
'add': {
'products': [{
'name': mmProduct.name,
'id': mmProduct.id,
'price': mmProduct.price,
'quantity': mmProduct.qty
}]
}
},
'eventCallback': function () {
//Are we on a product detail page with a form, or just a shopping page with a link?
if (pdp) {
jQuery('form.cart').submit(); //This part works just fine
} else {
mmProduct = null;
shopCartBtnClicked = true;
$(clickedLink).trigger('click'); //This doesn't
}
}
});
}
});
Its not very well done, but this should work:
var shopCartBtnClicked = false;
var clickedLink;
jQuery('.add_to_cart_button').click(function(e) {
if (shopCartBtnClicked === true) {
shopCartBtnClicked = false;
// dont return, just let javascript handle this one
} else {
// only execute when you have not set it to true
e.preventDefault();
clickedLink = this;
shopCartBtnClicked = true;
$(clickedLink).trigger('click');
}
});
I do have to wonder why you don't just execute your other logic first and then not prevent default anyway.
Taking #somethinghere's answer, your code can further be simplified to improve readability:
var shopCartBtnClicked = false;
jQuery('.add_to_cart_button').click(function(e) {
if( shopCartBtnClicked ) {
shopCartBtnClicked = false;
// dont return, just let javascript handle this one
} else {
// only execute when you have set it to true
e.preventDefault();
shopCartBtnClicked = true;
this.click();
}
});
Or, as suggested by #Regent:
var shopCartBtnClicked = false;
jQuery('.add_to_cart_button').click(function(e) {
shopCartBtnClicked = !shopCartBtnClicked;
if( shopCartBtnClicked ) {
e.preventDefault();
this.click();
}
});
OK guys, thank you for helping me get there. Normally, all of the other answers would work great, but for this specific tag manager instance, it appears (for some unknown reason), document.location works in the event callback fine here. This works.
It's weird because I used $(this).('form.cart').submit(); in a callback earlier in the code.
'eventCallback': function () {
//Are we on a product detail page with a form, or just a shopping page with a link?
if (pdp) {
jQuery('form.cart').submit();
} else {
mmProduct = null;
document.location = $(clickedLink).attr('href');
//$(clickedLink).trigger('click');
}
}
I know a solution for double/multi click on angularJS that disable on button click & enable it after completing ajax processing using ng-disabled. Please suggest any other best solution for handling double click in angularJS...
Our code will call ajax method on button click & will take small amount of tme to process & get data from db. We have to restrict second/ multi clicks mean while.
I don't want to allow click when ajax in progress...
Welcome Please be simple solutions rather than using ng-disabled, I am learner of AngularJS
createDialogService('ajs/common/templates/popup/config_reminder_popup.html',
{
title: isFrom,
backdrop: true,
controller: 'configRemindersCBController',
footerTemplate: '' + action + ''
});
$scope.saveOrUpdateReminder = function (reminder)
{
if ($scope.isDisabled)
{
return;
}
$scope.isDisabled = true;
if (!reminder.daysBeforeAfterCheckDate || reminder.daysBeforeAfterCheckDate === '')
{
alertService.openValidatPopup('Please enter days before expiration.', "Error", true, 'configRemindersCBController', 'Ok', 'u1_remove.png');
$scope.isDisabled = false;
return;
}
configRemindersService.isDaysBeforeAfterCheckDate($scope.objectId, reminder, function (result)
{
if (!reminder.selectedMessageTemplate.messageId || reminder.selectedMessageTemplate.messageId === '')
{
alertService.openValidatPopup('Please select message template.', "Error", true, 'configRemindersCBController', 'Ok', 'u1_remove.png');
$scope.isDisabled = false;
return;
}
else if (!reminder.selectedReminderSendOption.reminderSendOptionValue || reminder.selectedReminderSendOption.reminderSendOptionValue === '')
{
alertService.openValidatPopup('Please select reminder send option.', "Error", true, 'configRemindersCBController', 'Ok', 'u1_remove.png');
$scope.isDisabled = false;
return;
}
var enableReminder;
if (result.Result === 'No')
{
if (reminder.enable === true)
{
enableReminder = 'Enable';
}
else
{
enableReminder = 'Disable';
}
configRemindersService.addOrUpdateReminderConfigLine($scope.objectId, reminder, enableReminder, function (remindersResponse)
{
var reminder = remindersResponse.reminderConfigLine;
$rootScope.CONFIG = JSON.parse(remindersResponse.configData);
$scope.$modalClose();
$scope.isDisabled = false;
_.filter(configRemindersService.getMessageTemplates(), function (msg)
{
if (reminder.messageTemplateId === msg.messageId)
{
reminder.selectedMessageTemplate = msg;
}
});
_.filter(configRemindersService.getReminderSendOptions(), function (option)
{
if (reminder.reminderSendOption === option.reminderSendOptionValue)
{
reminder.selectedReminderSendOption = option;
}
});
if (configRemindersService.getIsFrom() === 'Create Reminder')
{
configRemindersService.getReminders().push(reminder);
}
else
{
configRemindersService.getReminders()[configRemindersService.getIndex()] = reminder;
}
});
}
});
};
ng-disabled is definitely the proper way to go with this -- it's a ready-made directive for disabling an object under certain conditions.
If you need to disable it without it looking disabled, you have 2 options:
Change the css for the disabled state to look like it's enabled.
Mimic this with a scope variable that only performs the actions when set.
For the second:
$scope.stopClick = false;
$scope.buttonClick = function () {
if ($scope.stopClick) { return; }
$scope.stopClick = true;
<.. code ..>
callback: function(data) {
$scope.stopClick = false;
}
};
This will accomplish the goal, but it's reinventing the wheel and is likely less robust than just disabling the element and restyling it.
Well you could do something like this :
Create a $scope variable
$scope.myFunnyPromise = null;
in the template :
<button ng-if="myFunnyPromise == null"></button>
Only show the button if myFunnyPromise equals null.
And in your function :
if($scope.myFunnyPromise !== null){
return $scope.myFunnyPromise;
}
$scope.myFunnyPromise = asyncTask().finally(function cleanUp(){
//clear the $scope variable
$scope.myFunnyPromise = null;
})
You can have a function in $rootScope which contains information about whether there is an ongoing http request. Then you can use that value to disable the buttons that you don't want successive click events.
I usually use fieldset attribute to disable input fields while there is an ongoing http request.
<fieldset ng-disabled="isWaitingForServerResponse()"> //when there is an ongoing request, input fields under this tag will be disabled </fieldset>
For implementing isWaitingForServerResponse I got help from a busy bar implementation, which shows a loading bar while there is a http request. It creates events when there is a new request and another request when it stops. So in these events I incremented a counter which holds the number of active http requests and decrement it for each http response. I haven't used it before but I guess you can also use the $http.pendingRequests property too for understanding whether there is a pending http request.
$rootScope.numberOfResponseWaitingFromServer = 0;
$rootScope.$on("cfpLoadingBar:loading", function (event) {
$rootScope.numberOfResponseWaitingFromServer++;
});
$rootScope.$on("cfpLoadingBar:loaded", function (event) {
$rootScope.numberOfResponseWaitingFromServer--;
});
$rootScope.isWaitingForServerResponse = function () {
return $rootScope.numberOfResponseWaitingFromServer > 0;
}
Using tutorials found i'm currently loading new pages with this:
$("a.nav-link").click(function (e) {
// cancel the default behaviour
e.preventDefault();
// get the address of the link
var href = $(this).attr('href');
// getting the desired element for working with it later
var $wrap = $('#userright');
$wrap
// removing old data
.html('')
// slide it up
.hide()
// load the remote page
.load(href + ' #userright', function () {
// now slide it down
$wrap.fadeIn();
});
});
This loads the selected pages perfectly, however the pages have forms that themselves use ajax to send the following:
var frm = $('#profileform');
frm.submit(function (ev) {
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
alert(data)
}
});
However this is not sending the form as it did before the page itself was called to the parent page via ajax. Am I missing something? Can you not use an ajax call in a page already called by ajax?
I also have other issues, for example I disable the submit button unless there are any changes to the form, using:
var button = $('#profile-submit');
var orig = [];
$.fn.getType = function () {
return this[0].tagName == "INPUT" ? $(this[0]).attr("type").toLowerCase() : this[0].tagName.toLowerCase();
}
$("#profileform :input").each(function () {
var type = $(this).getType();
var tmp = {
'type': type,
'value': $(this).val()
};
if (type == 'radio') {
tmp.checked = $(this).is(':checked');
}
orig[$(this).attr('id')] = tmp;
});
$('#profileform').bind('change keyup', function () {
var disable = true;
$("#profileform :input").each(function () {
var type = $(this).getType();
var id = $(this).attr('id');
if (type == 'text' || type == 'select') {
disable = (orig[id].value == $(this).val());
} else if (type == 'radio') {
disable = (orig[id].checked == $(this).is(':checked'));
}
if (!disable) {
return false; // break out of loop
}
});
button.prop('disabled', disable);});
However this also doesn't work when pulled to the parent page. Any help much appreciated! I'm really new to ajax so please point out any obvious mistakes! Many thanks in advance.
UPDATE
Just an update to what i've found. I've got one form working by using:
$(document).on('mouseenter', '#profile', function() {
However the following:
$(document).on('mouseenter', '#cancelimage', function() {
$('#cancelimage').onclick=function() {
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
} }; });
Is not working. I understand now that I need to make it realise code was there, so I wrapped all of my code in a mouseover for the new div, but certain parts still don't work, so I gave a mouseover to the cancel button on my image form, but when clicked it doesn't do any of the things it's supposed to.
For anyone else who comes across it, if you've got a function name assigned to it, it should pass fine regardless. I was trying to update it, and there was no need. Doh!
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
};
Works just fine.
I am trying to prevent duplicated data to database when the user click the submit button multiple times within a very short time (eg double click speed). First I disable the button after one click, then enable the button again after 3 seconds. I don't know why setTimeout("this.disabled=false",3000); is not working on jquery. Please help me out, below is my codes :
$(function() {
$(".btnSendResp").click(function() {
this.disabled = true;
setTimeout("this.disabled=false",3000);
postinResp();
});
});
You have the wrong this.
You need to save a reference to this in a local variable, then pass a function to setTimeout that uses the variable.
For example:
var self = this;
setTimeout(function() {
self.disabled = false;
}, 3000);
$(function() {
$(".btnSendResp").click(function() {
var that = this;
that.disabled = true;
setTimeout(function(){
that.disabled=false;
},3000);
postinResp();
});
});