javascript function is not a function but it is - javascript

I'm trying to make a HTML button trigger a function called switch_user, but every time I try clicking it, the console says switch_user is not a function.
This is the button:
<input type="button" class="btn btn-login" onclick="switch_user()" id="switch_user" value="{%trans%}Switch{%endtrans%}">
At the bottom of the page I have a script tag, with this function in it:
function switch_user(){
$("#switch-success, #switch-error").addClass("hide");
$.getJSON("/api/business/admin/swaproles?module="+$("#module").val()+"&user_from="+$("#user_from").val()+"&user_to="+$("#user_to").val(), function(data){
if(data) {
if(data["error"]){
$("#switch-error").html( "{%trans%}There was an error{%endtrans%}: " + data["error"]);
$("#switch-error").removeClass("hide");
}
else {
$("#switch-success").html("{%trans%}User was switched successfully{%endtrans%}");
$("#switch-success").removeClass("hide");
}
if(data["success"] == "ok") {
$("#elements").html("");
}
} else {
$("#switch-error").html("Critical failure - Please contact support");
$("#switch-error").removeClass("hide");
}
});
}
When I try to run the function manually from the console, it can find it just fine, but the buttons onclick refuses to recognize it. What am I doing wrong?

The issue is because the id of the element and the function name are the same. As they both exist under the window scope, there is a conflict. To fix the immediate problem either change the name of the function or the id of the element.
Better still, remove the outdated on* event attribute completely and use unobtrusive JS code to attach the event handler. As you're using jQuery already, here's how to do that:
<input type="button" class="btn btn-login" id="switch_user" value="{%trans%}Switch{%endtrans%}">
$(function() {
$('#switch_user').on('click', function() {
var $switchSuccess = $('#switch-success').addClass('hide');
var $switchError = $('#switch-error').addClass('hide');
$.getJSON("/api/business/admin/swaproles?module=" + $("#module").val() + "&user_from=" + $("#user_from").val() + "&user_to=" + $("#user_to").val(), function(data) {
if (data) {
if (data["error"]) {
$switchError.html("{%trans%}There was an error{%endtrans%}: " + data["error"]).removeClass("hide");
} else {
$switchSuccess.html("{%trans%}User was switched successfully{%endtrans%}").removeClass("hide");
}
if (data["success"] == "ok") {
$("#elements").html("");
}
} else {
$switchError.html("Critical failure - Please contact support").removeClass("hide");
}
});
})
});

Change the id . don't keep the id of element and function name same.
The JavaScript DOM bindings allow indexing by HTML id. Functions and properties share the same namespace in JavaScript. So, when an id in your HTML has the same name as one of your functions or properties, you can get logic errors that are hard to track down. While this is more of a CSS best practice issue, it’s important to remember when you can’t solve your javascript issue.

Related

Embed javascript function within another javascript function

I have a form with a conditional field that is only shown if the user selects a radio button for "other." If I remove the conditional on this field, my original javascript function works; however, with the conditional I can not get it to fire correctly.
The form has an event "cf.add" that fires when a conditional field is made visible, and using this jquery I get a correct response in the console:
jQuery( document ).on( 'cf.add', function(){
console.log('cf.add triggered' );
});
And if I remove the conditional so that this field is rendered when the page is rendered, I get the correct response in this field, which is to add a '$':
$("#fld_3169487_4").on("blur", handleChange);
function handleChange() {
var myValue = document.getElementById("fld_3169487_4").value;
if (myValue.indexOf("$") != 0)
{
myValue = "$" + myValue;
}
document.getElementById("fld_3169487_4").value = myValue;
}
I've tried putting this second function within the first, but no luck. I feel like I'm adding them in the incorrect order when I try to combine the two, I'm not sure what I'm doing wrong though.
I've also tried to call the function handleChange() on the 'cf.add' trigger, but that did not work for me either.
After some playing around, I figured it out:
jQuery( document ).on( 'cf.add', function(){
var otherField = $("#fld_3169487_3");
otherField.focus();
var dollarValue;
$(otherField).on("blur", function() {
dollarValue = otherField.val();
if (dollarValue.indexOf("$") != 0) {
dollarValue = "$ " + dollarValue;
}
$(otherField).val(dollarValue);
});
});
Since cf.add is an custom even that is published by your form, you can have other elements subscribe to the event:
$("#fld_3169487_4").on('cf.add', function(event){
if ($(this).val().indexOf("$") != 0)
{
$(this).val("$" + $(this).val());
}
});
Using $(this), we can target just the field the event is attached to. Additionally, data from the event publisher can be passed to the subscribers via the event argument.

Using onclick on an <a> element

I have an a element containing an href attribute. Clicking on it would delete data so I want the user to confirm that action. The href attribute refers to a php file with an id of the data that will be deleted in the GET parameter. I've added an onclick attribute, that should execute the following piece of JS (it shows a Semantic UI modal that asks for confirmation):
confirmmodal = function () {
beforeunload = function () {
$('.ui.basic.modal')
.modal({
closable: false,
onDeny: function () {
return false;
},
onApprove: function () {
return true;
}
})
.modal('show')
;
}
}
But when I run this it still goes to the page that would delete the data (although I haven't built it yet, so nothing is deleted). Would there be an option that gives the onclick attribute priority over the href attribute somehow?
You need to add event.preventDefault() at the end of your code.
Eg:
Delete
function showDialog(e) {
// custom code to show dialog here
e.preventDefault();
}
Okay, I got there with a few tweaks on the script, taking gavgrif's comment into account as well.
I made the <a> element a little different, so it won't contain an href attribute anymore:
<a title="Delete post" onclick="confirmmodal(this)" data-postid="'. $row['postnr'] .'"><i class="large delete middle aligned icon"></i></a>
Now, if the icon is clicked, the postid is available for the JS as well, so we can just refer to that in the GET parameter when the confirm button is clicked:
confirmmodal = function (a) {
$('.ui.basic.modal')
.modal({
closable: false,
onDeny: function () {
return true;
},
onApprove: function () {
window.location.href = "deletepost.php?id=" + a.dataset.postid
return true;
}
})
.modal('show')
;
}
Which is a semi-ugly fix, but it's not that many more lines, and I don't know s*** about JQuery :)
Thanks for all the help, I almost got there with preventDefault() but I couldn't continue if the action was confirmed, so this is an easier solution.

jquery function to handle a series of href in div rows

Imagine a table (actually constructed of divs) with rows and in the final cell in each row, I have an input text and a link that look like this:
<input type="text" name="message" id="message_#Model.IncidentId" value="">
Send a Comment
After each row (the parent div), I have a chunk of code like the following to ajaxify the link and text input:
$('#send_#Model.IncidentId').click(function () {
var msg = $('#message_#Model.IncidentId').val();
if (msg != '') { $(this).attr('href', this.href + '?msg=' + msg) }
$.post(this.href, function (json) {
if (json.jsonResult === null) {
$("#msg_#Model.IncidentId").html("Sent...");
} else {
window.location.href = json.jsonResult;
}
});
return false;
});
It works. However, there are at least 10 of these on each page. What I'm trying to do is consolidate the jquery into one function to handle all the links. Can I use jquery "this" or pass the IncidentId to the jquery function or something? It seems like "this" would not work because the input text is outside of the link? How can I do this to have one function for the entire page?
Keep in mind it's not imperative that I splash everything with the IncidentId. So, if I need to make one or more of the ids or names generic, that would be ok. It just needs to not get confused about what pair it's handling. I've seen some comments that a form might help, but 10+ forms on a page is ok? Plus, as it stands, there will never be any other input fields than what is shown above.
I appreciate your help. Thanks.
Update: So, I basically used Søren's recommended html5 data-* (data-id) attribute in my link, gave it a class name, and then moved my url down to the function as well...and then simply replaced all my #Model.IncidentIds. The one catch is that I had to use the following to register my click event:
$(document).on('click', ".ajax-link", function () {
I guess because I'm using handlebars to dynamically generate the page? I hadn't tested the original function since I moved it to my infinite scroll layout mentioned in the comments. Thanks all for replying.
Try this:
<input type="text" name="message" data-input-id="1" value="">
<a class="ajax-link" href="#" data-link-id="1">Send a Comment</a>
$('.ajax-link').click(function () {
var id = $(this).attr('data-link-id');
var msg = $('[data-link-id='+id+']').val();
if (msg != '') { $(this).attr('href', this.href + '?msg=' + msg) }
$.post(this.href, function (json) {
if (json.jsonResult === null) {
$("[data-link-id='+id+']").html("Sent...");
} else {
console.debug(json.jsonResult);
}
});
return false;
});
Make sure the link and field have the same id
First, make sure you have some useful class name's in place. E.g.,
<input type="text" class="incident-message" name="message" id="message_#Model.IncidentId" value="">
Send a Comment
That should allow you to create a nice, row-generic script like this:
$('.incident-link').click(function(e) {
e.preventDefault();
var $this = $(this),
$row = $this.closest('div'),
$msg = $row.find('.incident-message');
var msg = $msg.val();
if (msg != '') {
$this.attr('href', $this.attr('href') + '?msg=' + msg);
}
$.post($this.attr('href'), function (json) {
if (json.jsonResult === null) {
// I didn't see any markup for your #msg element, but assuming
// that you give it a useful classname, you can do something
// similar to this:
$row.find('.some-msg-className').html('Sent...');
} else {
window.location.href = json.jsonResult;
}
});
});
As far as grouping the events to a single handler, just use a class instead of id's.
$('.thisKind').click(function () {
or if the content is dynamic, use a single event for the parent with a selector in the on() method
$('#parentId').on("click", ".thisKind", function() {
As far as the this usage, you should familiarize yourself with jquery's DOM traversal using closest() to go up the tree and find() to go down

JQuery PHP / HTML switch onclick

This piece of code is somehow not working and I dont know why, im not good at php nor js just trying to make some website.
The part that is not working is this favorite button, it works like it has to work but it does not switch to "unfavorite" after click, it only works if u refresh the browser.
This is the html that is generated by the php file:
<a class="btn" id="fav28" title="Add to Favorites" href="javascript:;" onclick="AddFav('28','fav','add')">
<i class="icon-heart"></i>
</a>
And this is the js function:
function AddFav(id, dothis, dowhat) {
$.ajax({
url: ("/process.php?do="+dothis+"&id="+id+"&action="+dowhat)
});
if(dowhat == "add"){
document.getElementById(dothis+id).className = 'disabled';
document.getElementById(dothis+id).onclick = another_function
document.getElementById(dothis+id).title = 'Remove from Favorites';
}else if(dowhat == "remove"){
document.getElementById(dothis+id).className = 'btn';
document.getElementById(dothis+id).title = 'Add to Favorites';
}
}
I have tried the
document.getElementById(dothis+id).onClick = "AddFav(28,id,remove)";
but nothing happens with this, it simply does not change the onclick
what it has to do is to change the "onclick" event from
onclick="AddFav('28','fav','add')"
to
onclick="AddFav('28','fav','remove')"
Thanks in advance.
I might be wrong, but I don't think you can override the "onclick" attribute in HTML with JavaScript. The "onclick" will always run, even if you try to change it or add another click handler in JavaScript.
Your best solution for this problem would be to remove the "onclick" attribute, and setup the click handler with JavaScript instead.
Your PHP should generate this:
<a class="btn" id="fav28" title="Add to Favorites" href="javascript:;">
<i class="icon-heart"></i>
</a>
Note that "onclick" was removed. In your JS you should have something like this:
var favButton = document.getElementById('fav28');
favButton.addEventListener( 'click', function(){
// Note: `this` is referring to the button you clicked
if( this.className === 'disabled' ) {
// Run AddFav as if you were removing the favourite
this.className = 'btn';
this.title = 'Add to Favourites';
} else {
// Run AddFav as if you were adding the favourite
this.className = 'disabled'
this.title = 'Remove from Favourites';
}
});
Then your AddFav method only has to worry about adding or removing the favourite, which in your case looks like it's only an Ajax call. You can remove all logic from AddFav that changes the button and call it where I've commented out.
You says you tried
document.getElementById(dothis+id).onClick = "AddFav(28,id,remove)";
but the syntax is wrong because you don't have qoutes for id and remove (that are strings) like:
AddFav(28,'id','remove')";
I see you use jquery.. if you use jquery why not enjoy all features. your function can became:
function AddFav(id, dothis, dowhat) {
$.ajax({
url: ("/process.php?do="+dothis+"&id="+id+"&action="+dowhat)
});
if(dowhat == "add"){
$('#' + dothis + id).addClass('disabled'); // add class disabled
$('#' + dothis + id).removeClass('btn'); // remove class btn if exist
$('#' + dothis +id).on( "click", function() {
AddFav(id,'fav','remove'); // attach new function AddFav for click event
});
$('#' + dothis +id).attr('title','Remove from Favorites');
}
else if(dowhat == "remove"){
$('#' + dothis + id).addClass('btn'); // add class btn
$('#' + dothis + id).removeClass('disabled'); // remove class btn if exists
$('#' + dothis +id).attr('title','Add to Favorites');
}
}
If you want to do it in pure javascript than the changing the onclick attribute to another function is done like this:
document.getElementById(dothis+id).onclick = function { AddFav(id,'fav','remove') };
Like this:
http://jsfiddle.net/4ku75/
It might be a scope problem: the AddFav function might not be defined in the global scope.
Try replacing
function AddFav(id, dothis, dowhat) {
with
window.AddFav = function(id, dothis, dowhat) {
This way, your AddFav function is global, and you might call it using window.AddFav or simply AddFav

How to execute .click() code when previous click binding finishes

I am trying to use a Twitter Bootstrap button group with data-toggle="buttons-radio" in my site. Bootstrap markup as follows.
<div class="btn-group program-status" data-toggle="buttons-radio">
<button class="btn">All</button>
<button class="btn">Active</button>
<button class="btn">Planning</button>
<button class="btn">End of Life</button>
<button class="btn">Cancelled</button>
</div>
I need to redirect to the same page with query depending on the pressed button. I tried to use following jQuery code to achieve this.
<script>
var sParamStr = '';
function addToParamStr(str) {
sParamStr += str;
}
function redirectToUpdatedLocation() {
$('.program-status > .btn.active').each(function () {
addToParamStr( '?status=' + $(this).text());
});
console.log(sParamStr);
window.location.href = "program" + sParamStr;
}
$document.ready(function () {
$('.program-status > .btn').on('click', function (e) {
redirectToUpdatedLocation();
});
});
</script>
But the browser always redirects to {site}/program without the query string. By commenting out window.location.href = "program" + sParamStr; line, I managed to observe that second click onwards, sParamStr getting appended properly.
It seems that, my code tries to read the text of the pressed button before, .button('toggle') method form bootstrap.js finished. Code worked as intended when I changed function as follows.
$document.ready(function () {
$( '.program-status > .btn').on('click', function (e) {
$(this).addClass('active');
redirectToUpdatedLocation();
});
});
While this method works for me right now, I would like to know the proper way to achieve this. i.e How to execute my code after previous click binding finishes?
UPDATE:
I found this link in the Twitter Bootstrap forum. Seems it is a known issue.
https://github.com/twitter/bootstrap/issues/2380
I'm not sure what Bootstrap's .toggle is doing exactly, but it seems like it does some sort of animation that completes with the setting of the active class. You can try enqueing your code instead:
$( '.program-status > .btn').on('click', function (e){
$(this).queue(function (next) {
redirectToUpdatedLocation();
next();
});
});
For example, click the div as it is being toggled: http://jsfiddle.net/9HwYy/
It also seems a bit silly to me to update every href instead of just the one you clicked on since you are changing the window location anyway.
try
$('.program-status > .btn.active').each(function(i,v){
v = $(v);
addToParamStr( '?status=' + v.text());
});
since im not sure "this" is working in your case.

Categories