(First of all English is not my native language, I'm sorry if I'll probably be mistaken).
I've created Yii Web app where is input form on the main page which appears after button click through ajax request. There is a "Cancel" button on the form that makes div with form invisible. If I click "Show form" and "Cancel" N times and then submit a form with data the request is repeating N times. Obviously, browser binds onclick event to the submit button every time form appears. Can anybody explain how to prevent it?
Thank you!
I've had the exact same problem and there was a discussion about it in the Yii Forum.
This basically happens because you are probably returning ajax results with "render()" instead or renderPartial(). This adds the javascript code every time to activate all ajax buttons. If they were already active they will now be triggered twice. So the solution is to use renderPartial(). Either use render the first time only and then renderPartial(), or use renderPartial() from the start but make sure the "processOutput" parameter is only set to TRUE the first time.
Solved!
There was two steps:
First one. I decided to add JS code to my CHtml::ajaxSubmitButton instance that unbind 'onclick' event on this very button after click. No success!
Back to work. After two hours of digging I realized than when you click 'Submit' button it raises not only 'click' event. It raises 'submit' event too. So you need to unbind any event from whole form, not only button!
Here is my code:
echo CHtml::submitButton($diary->isNewRecord ? 'Создать' : 'Сохранить', array('id' => 'newRecSubmit'));
Yii::app()->clientScript->registerScript('btnNewRec', "
var clickNewRec = function()
{
jQuery.ajax({
'success': function(data) {
$('#ui-tabs-1').empty();
$('#ui-tabs-1').append(data);
},
'type': 'POST',
'url': '".$this->createUrl('/diary/newRecord')."',
'cache': false,
'data': jQuery(this).parents('form').serialize()
});
$('#new-rec-form').unbind();
return false;
}
$('#newRecSubmit').unbind('click').click(clickNewRec);
");
Hope it'll help somebody.
I just run into the same problem, the fix is in the line that starts with 'beforeSend'. jQuery undelegate() function removes a handler from the event for all elements which match the current selector.
<?php echo CHtml::ajaxSubmitButton(
$model->isNewRecord ? 'Add week(s)' : 'Save',
array('buckets/create/'.$other['id'].'/'.$other['type']),
array(
'update'=>'#addWeek',
'type'=>'POST',
'dataType'=>'json',
'beforeSend'=>'function(){$("body").undelegate("#addWeeksAjax","click");}',
'success'=>'js:function(data) {
var a=[];
}',
),
array('id'=>'addWeeksAjax')
); ?>
In my example I've added the tag id with value 'addWeeksAjax' to the button generated by Yii so I can target it with jQuery undelegate() function.
I solved this problem in my project this way, it may not be a good way, but works fine for me: i just added unique 'id' to ajax properties (in my case smth like
<?=CHtml::ajaxLink('<i class="icon-trash"></i>',
$this->createUrl('afisha/DeletePlaceAjax',
array('id'=>$value['id'])),
array('update'=>'.data',
'beforeSend' => 'function(){$(".table").addClass("loading");}',
'complete' => 'function(){$(".table").removeClass("loading");}'),
array('confirm'=>"Уверены?",'id'=>md5($value['id']).time()))
?>
).
Of course, you should call renderPartial with property 'processOutput'=true. After that, everything works well, because every new element has got only one binded js-action.
text below copied from here http://www.yiiframework.com/forum/index.php/topic/14562-ajaxsubmitbutton-submit-multiple-times-problem/
common issue...
yii ajax stuff not working properly if you have more than one, and if
you not set unique ID
you should make sure that everything have unique ID every time...
and you should know that if you load form via ajax - yii not working
well with it, cause it has some bugs in the javascript code, with die
and live
In my opinion you should use jQuery.on function. This will fire up event on dynamically changed content. For example: you're downloading some list of images, and populate them on site with new control buttons (view, edit, remove). Example structure could looks like that:
<div id="img_35" class='img-layer'>
<img src='path.jpg'>
<button class='view' ... />
<button class='edit' ... />
<button class='delete' ... />
</div>
Then, proper JS could look like this ( only for delete, others are similiar ):
<script type="text/javascript">
$(document).on('click', '.img-layer .delete', function() {
var imgId = String($(this).parent().attr('id)).split('_')[1]; //obtain img ID
$.ajax({
url: 'http://www.some.ajax/url',
type : 'POST',
data: {
id: imgId
}
}).done({
alert('Success!');
}).fail({
alert('fail :(');
});
}
</script>
After that you don't have to bind and unbind each element when it has to be appear on your page. Also, this solutiion os simple and it's code-clean. This is also easy to locate and modify in code.
I hope, this could be usefull for someone.
Regards
. Simon
Related
I am learning ASP.NET MVC. I have to submit a to controller side after validation in client-side(in jquery). How this can be done? Should i use <form action="#" method="post"> instead of <form action="Controller/Method" method="post"> and add an event handler in click event of submit button of , to send via ajax etc? What should i do? pls help
You are on the right track, and what you suggested will work.
A better method would be to leave the original action intact, providing backwards compatibility to older browsers. You would then create the event handler as normal, and include code to prevent the default submit behavior, and use ajax instead.
$('#submitbutton').live('click', function(e){ e.preventDefault(); });
The easiest way to do this is to use the jQuery forms plugin.
This is my go-to plugin for this type of thing. Basically it will take your existing form, action url etc and convert the submission to an ajax call automatically. From the website:
The jQuery Form Plugin allows you to easily and unobtrusively upgrade
HTML forms to use AJAX. The main methods, ajaxForm and ajaxSubmit,
gather information from the form element to determine how to manage
the submit process. Both of these methods support numerous options
which allows you to have full control over how the data is submitted.
It is extremely useful for sites hosted in low cost web hosting
providers with limited features and functionality. Submitting a form
with AJAX doesn't get any easier than this!
It will also degrade gracefully if, for some reason, javascript is disabled. Take a look at the website, there are a bunch of clear examples and demos.
This is how I do:
In jQuery:
$('document').ready(function() {
$('input[name=submit]').click(function(e) {
url = 'the link';
var dataToBeSent = $("form#myForm").serialize();
$.ajax({
url : url,
data : dataToBeSent,
success : function(response) {
alert('Success');
},
error : function(request, textStatus, errorThrown) {
alert('Something bad happened');
}
});
e.preventDefault();
});
In the other page I get the variables and process them. My form is
<form name = "myForm" method = "post">//AJAX does the calling part so action is not needed.
<input type = "text" name = "fname"/>
<input type= "submit" name = "submit"/>
<FORM>
In the action page have something like this
name = Request.QueryString("fname")
UPDATE: As one of your comment in David's post, you are not sure how to send values of the form. Try the below function you will get a clear idea how this code works. serialize() method does the trick.
$('input[name=submit]').click(function(e){
var dataToBeSent = $("form#myForm").serialize();
alert(dataToBeSent);
e.preventDefault();
})
I have a Razor/ASP/MVC3 web application with a form and a Submit button, which results in some action on the server and then posts back to the form. There is often some delay, and it's important that users know they should wait for it to complete and confirm before closing the page or doing other things on the site, because it seems users are doing that and sometimes their work has not been processed when they assume it has.
So, I added a "Saving, Please Wait..." spinner in a hidden Div that becomes visible when they press the Submit button, which works very nicely, but I haven't been able to find a way to get the Div re-hidden when the action is complete.
My spinner Div is:
<div id="hahuloading" runat="server">
<div id="hahuloadingcontent">
<p id="hahuloadingspinner">
Saving, Please Wait...<br />
<img src="../../Content/Images/progSpin.gif" />
</p>
</div>
</div>
Its CSS is:
#hahuloading
{
display:none;
background:rgba(255,255,255,0.8);
z-index:1000;
}
I get the "please wait" spinner to appear in a JS method for the visible button, which calls the actual submit button like this:
$(document).ready(function () {
$("#submitVisibleButton").click(function () {
$(this).prop('disabled', true);
$("#myUserMessage").html("Saving...");
$("#myUserMessage").show();
$("#hahuloading").show();
document.getElementById("submitHiddenButton").click();
});
});
And my view model code gets called, does things, and returns a string which sets the usermessage content which shows up fine, but when I tried doing some code in examples I saw such as:
// Re-hide the spinner:
Response.write (hahuloading.Attributes.Add("style", "visibility:hiddden"));
It tells me "hahuloading does not exist in the current context".
Is there some way I am supposed to define a variable in the view model which will correspond to the Div in a way that I can set its visibility back from the server's action handler?
Or, can I make the div display conditional on some value, in a way that will work when the page returns from the action?
Or, in any way, could anyone help me figure out how to get my div re-hidden after the server action completes?
Thanks!
Is this done with ajax? I would assume so because the page is not being redirected. Try this:
$(document).ready(function () {
$("#submitVisibleButton").click(function () {
$(this).prop('disabled', true);
$("#myUserMessage").html("Saving...");
$("#myUserMessage").show();
$("#hahuloading").show();
document.getElementById("submitHiddenButton").click();
});
$("#hahuloading").ajaxStop(function () {
$(this).hide();
});
});
As an aside, you no longer need runat=server.
What I want to achieve, is not the autocomplete effect. What I want to achieve is that when you type on google the search results come up almost inmediately without cliking on a search button.
I already did the ajax example with a search button, but I would like it to make it work while you type it shows the results in a table.
The problem is I have no idea where to start.
EDIT: To ask it in another way.
Lets suppose I have a grid with 1000 names. The grid is already present on the page.
I have a textbox, that when typing must filter that grid using AJAX, no search button needed.
Thanks
Use a PartialView and jQuery.ajax.
$(document).ready(function () {
$("#INPUTID").bind("keypress", function () {
if($(this).val().length > 2) {
$.ajax({
url: "URL TO CONTROLLER ACTION",
type: "POST|GET",
data: {query: $("#INPUTID").val(),
success: function (data, responseStatus, jQXHR)
{
$("#WRAPPERDIVID").html(data);
}
});
}
});
});
Then in your view:
<div>
<input type="text" id="INPUTID" />
</div>
<div id="WRAPPERDIVID"></div>
Edit
Also, you could build in some sort of timer solution that submits the request after say 1 second of no typing, so you don't get a request on every key press event.
Theres a good example you can check here try to type 's' in the search
if thats what you want
then the code and the tutorial is here
another good example here
If you are working on "filtering" a set already located on the page, then you seem to want to set the visibility of the items in the list, based upon the search criteria.
If so, then first, you need to first establish your HTML for each item. You can use the following for each item:
<div class="grid">
<div class="item"><input type="text" value="{name goes here}" readonly="readonly" /></div>
{ 999 other rows }
</div>
Then, you must use some jquery to set each row visible/invisible based on the search criteria:
$("#searchBox").live("change", function () {
$("div[class='grid'] input").each(function () {
var search = $("#searchBox").val();
if ($(this).val().toString().indexOf(search) != -1)
$(this).parent().show();
else
$(this).parent().hide();
});
});
This will cause the visibility of each item to change, depending on whether or not the text in the search box matches any text in the item.
I have a view with a button and a DIV
I am trying to have this kind of functionality:
if the button is clicked - a controller method is executed ( i have the method, db.insert, etc.)
- if test (inside the controller method) is passed the button dissapears and the div appears ( I thought at using ajax - not to refresh the hole page)
whenever the page is refreshed the test has to be made again for the button to be visible or not
thanks
Something like this?
{{=DIV(A('click me',callback=URL('mycallback'),target="me"),_id="me")}}
def mycallback():
# do whatever you need to do
return DIV("I will appear in place of he link when you click")
I looked in more of your examples and I think my problem was simpler ( if there isn't any other solution)
So what I did was I used eval:
button in view :
<input id="b_normal" type="button" value="normal" onClick="ajax('{{=URL('db_test')}}',[],':eval')" />
and the controller method:
def db_test()
#tests and updates
return "jQuery('#b_normal').fadeOut();jQuery('#commDiv').show();"
for further refresh i used jquery, in view:
jQuery(document).ready(function(){
var flag = '{{=flag_normal}}';
if(flag == 'da')
jQuery('#b_normal').hide();
else jQuery('#commDiv').hide();
});
where *flag_normal* is sent by the main controller
I hope this is not too inefficient and if so, useful
EDIT: The problem is not related to Boxy, I've run into the same issue when I've used JQuery 's load method.
EDIT 2: When I take out link.remove() from inside the ajax callback and place it before ajax load, the problem is no more. Are there restrictions for manipulating elements inside an ajax callback function.
I am using JQuery with Boxy plugin.
When the 'Flag' link on the page is clicked, a Boxy modal pops-up and loads a form via ajax. When the user submits the form, the link (<a> tag) is removed and a new one is created from the ajax response. This mechanism works for, well, 3 times! After the 3rd, the callback function just does not remove/replace/append (tested several variations of manipulation) the element.
The only hint I have is that after the 3rd call, the parent of the link becomes non-selectable. However I can't make anything of this.
Sorry if this is a very trivial issue, I have no experience in client-side programming.
The relevant html is below:
<div class="flag-link">
<img class="flag-img" style="width: 16px; visibility: hidden;" src="/static/images/flag.png" alt=""/>
<a class="unflagged" href="/i/flag/showform/9/1/?next=/users/1/ozgurisil">Flag</a>
</div>
Here is the relevant js code:
$(document).ready(function() {
$('div.flag-link a.unflagged').live('click', function(e){
doFlag(e);
return false;
});
...
});
function doFlag(e) {
var link = $(e.target);
var url = link.attr('href');
Boxy.load(url, {title:'Inappropriate Content', unloadOnHide:true, cache:false, behaviours: function(r) {
$("#flag-form").live("submit", function(){
var post_url = $("#flag-form").attr('action');
boxy = Boxy.get(this);
boxy.hideAndUnload();
$.post(post_url, $("#flag-form").serialize(), function(data){
par = link.parent();
par.append(data);
alert (par.attr('class')); //BECOMES UNDEFINED AT THE 3RD CALL!!
par.children('img.flag-img').css('visibility', 'visible');
link.remove();
});
return false;
});
}});
}
Old and late reply, but.. I found this while googling for my answer, so.. :)
I think this is a problem with the "notmodified" error being thrown, because you return the same Ajax data.
It seems that this is happening even if the "ifModified" option is set to false (which is also the default).
Returning the same Ajax data three times will cause issues for me (jQuery 1.4). Making the data unique (just adding time/random number in the response) removes the problem.
I don't know if this is a browser (Firefox), jQuery or server (Apache) issue though..
I have had the same problem, I could not run javascript after I call boxy. So I put all my javascript code in afterShow:function one of boxy attributes. I can run almost except submit my form. My be my way can give you something.