merging two similiar functions with .preventDefault() - javascript - javascript

I have two similar functions, function done and function delete.
I want to merge them together but I don't know how to merge them properly.
I did it in the back end for php but for javascript somehow I couldn't get it to work.
I have jquery for these two buttons let's say
I started with something like this which works fine and nothing wrong but I guess it'll be good for to merge them together since they are pretty similar.
$('ol#textField').on('click', '.done-btn', doneButton);
$('ol#textField').on('click', '.delete-btn', deleteButton);
my deleteButton and doneButtion functions
function deleteButton(e){
e.preventDefault();
var $clicked = $(this);
var $cLI = $clicked.closest('li');
var todoText = $cLI.clone().children().remove().end().text();
var getID = $cLI.attr('id');
$.ajax({
// codes
}
});
}
function doneButton(e){
e.preventDefault();
var $clicked = $(this);
var $cLI = $clicked.closest('li');
var $cSpan = $clicked.closest('span');
var todoText = $cLI.clone().children().remove().end().text();
var getID = $cLI.attr('id');
$.ajax({
//codes
}
});
}
as seen they are like the same but of course except the ajax part which I didn't add in since it'll be too much codes and I don't think those codes is any concern.
so I tried something like this to combine them but doesn't work.
$('ol#textField').on('click', '.done-btn', doubleD('done'));
$('ol#textField').on('click', '.delete-btn', doubleD('delete'));
I tried to combine the function like this. so if the parameter is done then the done ajax will be called and parameter is delete then delete will be called. I also want to add the .preventDefault() into the function but have no clue how to get them done.
function doubleD(action){
var $clicked = $(this);
var $cLI = $clicked.closest('li');
var todoText = $cLI.clone().children().remove().end().text();
var getID = $cLI.attr('id');
if(action == 'done'){
var $cSpan = $clicked.closest('span');
$.ajax({
// ajax for done
}
});
}
if(action == 'delete'){
$.ajax({
// ajax for delete
}
});
}
}
Can someone please give me a hand?
Thank you for your time and attention.

The problem is that jQuery doesn't pass your argument on to the handler. You have to add that as event data. Reference: http://api.jquery.com/on/
Try this:
$('ol#textField').on('click', '.done-btn', { action: 'done' }, doubleD);
$('ol#textField').on('click', '.delete-btn', { action: 'delete' }, doubleD);
Then you will access like this:
function doubleD(evt){
var action = evt.data.action; // ACCESS THE PARAMETER HERE
var $clicked = $(this);
var $cLI = $clicked.closest('li');
var todoText = $cLI.clone().children().remove().end().text();
var getID = $cLI.attr('id');
if(action == 'done'){
var $cSpan = $clicked.closest('span');
$.ajax({
// ajax for done
}
});
}
if(action == 'delete'){
$.ajax({
// ajax for delete
}
});
}
}
I don't recommend doing it this way, but you can also write it like this:
$('ol#textField').on('click', '.done-btn', function () {
doubleD('done');
});
$('ol#textField').on('click', '.done-btn', function () {
doubleD('delete');
});
Then, your original doubleD function would work.

have you simply tried this
$('ol#textField').on('click', '.done-btn, .delete-btn', function(e){
e.preventDefault();
if( $(this).hasClass('done-btn') ){
}else{
}
});
IF not $(this) you can use $(e.target) i am pretty sure too, checking the class will tell you the button, no?
To separate the call, the main difference is the scope it's being called in. When it's part of the event, then the $(this) has meaning, if it's separate then you lose that scope. To overcome that you can use the event object which contains the target of the event http://www.w3schools.com/jquery/event_target.asp, you have to be mind full of event bubbling though but I think in this case ( using an input ) you would be ok, you could check $(e.target).is('input[type="button"]') if you really wanted to be safe. Anyway:
$('ol#textField').on('click', '.done-btn, .delete-btn', doubleD);
function doubleD(e){
e.preventDefault();
if( $(e.target).hasClass('done-btn') ){
}else{
}
};
However as I said int the comments, separating the logic from the presentation ( using e.data ) has great value. What that means is that you are not relying on the class names for the logic. So if at a latter point you decide to change the class you don't need to update the code, because it's not relying on your presentation ( page layout and styling ).
I actually know about the other answer and planed on adding it as well, but as I don't use it much I had to do a bit of googling to make sure I remembered it correctly. The other poster beat me to it. Which is fine, but I wanted to point out it's actually a better method.
Also you could use a data- http://www.w3schools.com/tags/att_global_data.asp attribute instead of the class, like
<input type="button" class="done-btn" data-mode="done" />
And check it by doing
if( $(this).data('mode') == 'done' ){
...
Some may say that is not the "best practice" way of doing it so really the best way, still is to use the event.data. Because while it be less relent on the presentation, there is still that element of dependency on the DOM element.

Related

Exporting jQuery custom plugin

I really hope this question doesn't end marked as 'already answered' because I've minutely checked previous questions and my case, unfortunately, doesn't happen to be there.
I've already create a (working) jQuery function to transform a form into a JSON object so I can send it to the server (this is all with an educational purpose by the way, so please save your time before telling me to use a library lol) and even though is working great, I want to save it in a separate file so my main script doesn't look too awful.
(function ($) {
$.fn.formToJSON = function(){
let json = {};
if($(this).is('form')){
$.each($(this).find('input'), function(){
if(this.name && this.value){ //are not empty
if(this.type === 'checkbox' && this.checked){
json[this.name] = (json[this.name] || []).concat(this.value || ''); //check if exists
}else{
json[this.name]= this.value;
}
}
});
}
console.log(JSON.stringify(json));
}
})(jQuery);
What do I need to do to use it by just importing the script in the HTML file?
The followinglike function patters are not what I'm looking for in my script by the way.
(function($) {
$.fn.helloWorld = function() {
return this.each( function() {
$(this).text("Hello, World!");
});
}
}(jQuery));
I'd appreciate if someone could help me achieve the goal which is using my script like this (I can already use like that but it needs the function to be in the main script):
$('form').formToJSON();
Nevermind, I just figured out all I need to do is add several declarations of functions inside my IIF (Immediately Invoked Function) jQuery function.
(function($){
$.fn.logme = function(){
console.log(this);
}
$.fn.logHi = function(){
console.log('hi!');
}
})(jQuery)

How to show the result of this jQuery function without the need of clicking the button?

I have this function below, however I want to make it work on windows load and show the result without clicking the button.
This is the code I use https://raw.githubusercontent.com/SuyashMShepHertz/indexedDB_sample/master/index.html
How to do this?
$("#getBtn").click(function(){
var type = 'permanent';
var request = db.transaction(["hashes"],"readwrite").objectStore("hashes").get(type);
request.onsuccess = function(event){
$("#result").html("Name : "+request.result.name);
};
});
just put your code in
$( window ).load(function() {
//Code Here
});
If you need it both on click and initially when the page loads, make it a reusable function:
function doTheThing() {
var type = 'permanent';
var request = db.transaction(["hashes"], "readwrite").objectStore("hashes").get(type);
request.onsuccess = function(event) {
$("#result").html("Name : " + request.result.name);
};
}
Then call it from both places you need it:
On page load
On click
To call it on page load, just make sure your script is at the end of the HTML (just before the closing </body> tag; this is best practice unless you have a good reason for doing something else) and call it:
doTheThing();
If you can't put the script at the end of the HTML, you can use jQuery's ready callback instead:
// Concise, but easy to misunderstand:
$(doTheThing);
// Or more verbose but also more clear:
$(document).ready(doTheThing);
(See note below about doing it directly or indirectly.)
To call it on click, hook it up, either directly or indirectly:
// Directly
$("#getBtn").click(doTheThing);
// Or indirectly
$("#getBtn").click(function() {
doTheThing();
});
The only reason for hooking it up indirectly would be to avoid having it receive the event object jQuery will pass it automatically, and to avoid having its return value examined by jQuery to see if it should stop propagation and prevent the default event action.
To avoid creating globals, I'd make sure the entire thing is in a scoping function:
(function() {
function doTheThing() {
var type = 'permanent';
var request = db.transaction(["hashes"], "readwrite").objectStore("hashes").get(type);
request.onsuccess = function(event) {
$("#result").html("Name : " + request.result.name);
};
}
doTheThing();
$("#getBtn").click(doTheThing);
})();
just put it in $(document).ready, like this
$(document).ready(function(){
var type = 'permanent';
var request = db.transaction(["hashes"],"readwrite").objectStore("hashes").get(type);
request.onsuccess = function(event){
$("#result").html("Name : "+request.result.name);
};
});

listening for click event for an href by classname

there is a page with some basic HTML that I cannot touch that looks like this:
<a class="continue-shopping" href="https://someURL">Continue shopping</a>
what I want to do is send the user to a different link when they click on the someURL text link. the user can come to a page containing this html from many other pages.
i have tried many hours but cannot get my js to recognize a click event for a class associated with hyperlinked text. i could really use some help here. this is the js code i wrote which does not work
window.onload = function() {
prepEventHandler();
}
function prepEventHandler () {
var myClass = document.getElementsByClassName("continue-shopping");
myClass[0].onclick=window.open(document.referrer,"_self");
/* which make my pages go haywire OR THIS -- which also does not work */
myClass[0].addEventListener("click", function() {
window.open(document.referrer,"_self");
}
)
}
It just keeps ignoring the second function, and I am sure I am doing some really basic that is wrong. Again, thanks for any help!
Apart from preventDefault() you could also use return false
window.onload = function () {
var myClass = document.querySelector(".continue-shopping")
.onclick = function () {
window.location.href = "http://elsewere.com";
return false;
}
}
this code should work but it no longer does and i do not know why any hint much appreciated - there seems to be some problem with myClass[0]
window.onload = function() {
var myClass = document.getElementsByClassName('continue-shopping');
myClass[0].addEventListener("click", function(e) {
e.preventDefault();
window.location.href = document.referrer;
});
}

Simple client-side framework/pattern to simplify doing async calls?

We're currently not using any serious client side framework besides jQuery (and jQuery.ui + validation + form wizard plugins).
A problem that surfaces a few times in our code is this:
We have a button that initiates an Ajax call to the server.
While the call is taking place, we display a "loading" icon with some text
If the server returns a result too quickly (e.g. < 200 ms), we "sleep" for 200 millis (using setTimeout()), to prevent flickering of the waiting icon & text.
After max(the call returns, a minimal timeout), we clear the loading icon & text.
We then either display an error text, if there was some problem in the ajax call (the server doesn't return 500, but a custom json that has an "error message" property. In fact, sometimes we have such a property in the response per form field ... and we then match errors to form fields ... but I digress).
In case of success, we do ... something (depends on the situation).
I'm trying to minimize code reuse, and either write or reuse a pattern / piece of code / framework that does this. While I probably won't start using an entire new heavy-duty framework just for this use case, I would still like to know what my options are ... perhaps such a client-side framework would be good for other things as well. If there's a lightweight framework that doesn't require me to turn all my code upside down, and I could use just on specific cases, then we might actually use it instead of reinventing the wheel.
I just recently heard about Ember.js - is it a good fit for solving this problem? How would you solve it?
$(function(){
var buttonSelector = "#button";
$('body').on({'click': function(evt){
var $button = $(this);
$button.toggleClass('loading');
var time = new Date();
$.get('some/ajax').then(function(data,text,jqXhr){
// typical guess at load work
$button.empty();
$(data).wrap($button);
}).fail(function(data,text,jqXhr){
alert("failed");
}).done(function(data,text,jqXhr){
var elapsed = new Date();
if((elapsed - time) < 200){
alert("to short, wait");
}
$button.toggleClass('loading');
});
}},buttonSelector,null);
});
Just wrap the $.ajax in your own function. that way you can implement your own queing etc. I would suggest to do a jquery component for this. It can get pretty powerful, for example you can also pass http headers etc.
Regarding frameworks it depends on your requirements.
For example, you may consider Kendo UI, it has good framework for creating data sources:
http://demos.kendoui.com/web/datasource/index.html.
Working Sample Code (well, almost)
I was going for something along the lines of #DefyGravity's answer anyway - his idea is good, but is still pseudo-code/not fully complete. Here is my working code (almost working demo, up to the Ajax URL itself, and UI tweaks)
The code & usage example:
jQuery.fn.disable = function() {
$(this).attr("disabled", "disabled");
$(this).removeClass("enabled");
// Special handling of jquery-ui buttons: http://stackoverflow.com/questions/3646408/how-can-i-disable-a-button-on-a-jquery-ui-dialog
$(this).filter("button").button({disabled: true});
};
jQuery.fn.enable = function() {
$(this).removeAttr("disabled");
$(this).addClass("enabled");
// Special handling of jquery-ui buttons: http://stackoverflow.com/questions/3646408/how-can-i-disable-a-button-on-a-jquery-ui-dialog
$(this).filter("button").button({disabled: false});
};
function AjaxCallbackWaiter(ajaxUrl, button, notificationArea, loadingMessage, errorMessage, inSuccessHandler, inFailureHandler) {
// Every request that takes less than this, will be intentionally delayed to prevent a flickering effect
// http://ripper234.com/p/sometimes-a-little-sleep-is-ok/
var minimalRequestTime = 800;
var loadingIconUrl = 'http://loadinfo.net/images/preview/11_cyrcle_one_24.gif?1200916238';
var loadingImageContent = $("<img class='loading-image small' src='" + loadingIconUrl + "'/><span class='loading-text'>" + loadingMessage + "</span>");
var errorContentTemplate = $("<span class='error ajax-errors'></span>");
var requestSentTime = null;
button.click(clickHandler);
function displayLoadingMessage() {
clearNotificationArea();
notificationArea.html(loadingImageContent);
}
function clearNotificationArea() {
notificationArea.html("");
}
function displayError(message) {
var errorContent = errorContentTemplate.clone(errorContentTemplate).html(message);
notificationArea.html(errorContent);
}
function ajaxHandler(result) {
var requestReceivedTime = new Date().getTime();
var timeElapsed = requestReceivedTime - requestSentTime;
// Reset requestSentTime, preparing it for the next request
requestSentTime = null;
var sleepTime = Math.max(0, minimalRequestTime - timeElapsed);
function action() {
clearNotificationArea();
button.enable();
if (result) {
inSuccessHandler();
} else {
displayError(errorMessage);
inFailureHandler();
}
}
if (sleepTime <= 0) {
action();
} else {
setTimeout(action, sleepTime);
}
}
function failureHandler() {
}
function clickHandler(){
if (requestSentTime !== null) {
logError("Bad state, expected null");
}
requestSentTime = new Date().getTime();
displayLoadingMessage();
button.disable();
$.get(ajaxUrl, 'json').then(ajaxHandler, failureHandler);
}
}
// Usage:
var ajaxUrl = 'FILL IN YOUR OWN URL HERE';
var button = $("#clickme");
var notificationArea = $(".ajax-notification-area");
var waitingMessage = "Doing Stuff";
var errorMessage = "Not Good<br/> Please try again";
$(document).ready(function(){
new AjaxCallbackWaiter(
ajaxUrl,
button,
notificationArea,
waitingMessage,
errorMessage,
function(){
alert("All is well with the world");
},
function(){
alert("Not good - winter is coming");
});
});

Jquery simple function

The aim of this code is to delete a comment with AJAX. The function is called as follows:
DeleteComment(166);
And the code that runs is:
// Each delete button
function DeleteComment(CommentID) {
$.ajax({
url: AJAXURL + "?action=del&id=" + CommentID,
success: function (data) {
// Parse the data
if (data.substring(0, 1) == "1") {
$('#cid' + CommentID).hide();
} else {
alert(data.substring(2, data.length));
}
}
});
}
However the $('#cid' + CommentID).hide(); line never fires as CommentID isn't retained, I'm new to Jquery, could someone show me how to change this so the comments ID is retained when the ajax success is called?
put the $('#cid' + CommentID).hide(); before $.ajax({ and then add $('#cid' + CommentID).show(); to your else condition..
Hide it first and then reshow it if deletion fails...
Not the most graceful solution, but the path of least resistance from where you are.
Can you post more of the surrounding code? As is, your code looks like it should work. But I see a troublesome comment: // Each delete button. The way you are binding the DeleteComment function to the buttons must not be working the way you assume.
Try this instead:
// Iterate over each delete button.
// The .each(...) provides you a function, a.k.a. local scope, for each button.
$(".deleteButtons").each(function (idx, el) {
// This is very important: you must create a local variable to hold the ID.
// How to get the ID is up to you.
var id = getTheCorrespondingCommentId(idx, el);
// Now you can safely pass the local variable to the DeleteComment function:
$(el).click(function() { DeleteComment(id); });
});

Categories