Previous question for context: C# MVC 5 Razor: Updating a partial view with Ajax fails
Now that I have successfully managed to refresh my partial view, I find myself having another difficulty which I don't really know how to deal with. You see, the table I am displaying also displays two buttons per line:
<td class="noWrap width1percent tri">
<input type="button" value="Valider" id="Valider_#i" data-valid=data />
<input type="button" value="Rejeter" id="Rejeter_#i" data-reject=data />
</td>
That's a "validate" button and a "rejection" button. Basically, each line can either be "approved" or "rejected", and the user uses those buttons to make a decision for each line. The actions are bound to a Javascript script, put on top of the main view, which looks like this:
$(function () {
$('*[data-valid]')
.click(function () {
// Get values of fields
$("#divLoading").show();
var idOfField = this.id;
var data = document.getElementById(idOfField).dataset.valid;
// Partially censored code
// Now that we have the values of all fields we need to use a confirmation message
var result = confirm("OK?")
if (result == true) {
// The user chose to validate the data. We have to treat it.
validateResults(data);
}
else {
$("#divLoading").hide();
}
})
ValidateResults:
function validateResults(data) {
$.ajax({
url: '#Url.Action("ValidateControl", "Article")',
type: "POST",
data: { data:data},
success: function (result) {
$("#tableControl").html(result);
$("#divLoading").hide();
}
});
}
A similar function exists for the rejection button.
Now, before successfully managing to refresh my Partial View, this worked fine. However, now that the refreshing works, clicking the buttons after refresh doesn't work. I believe this is because the Javascript action isn't bound to the buttons once more after the refresh event is done!
How can I make sure that my Javascript actions, in the main view, are bound to the buttons which are generated in the partial view?
Please note that I tried to put the portion of the main view in the partial view, instead. This makes sure that the actions are bound once again, but completely kills the CSS after refresh, which isn't a desirable outcome either!
Since you are essentially replacing the body of the table, you will need to re-wire the events if you do it the way you are doing it. You can also hook the event up to the parent tbody:
$(document).ready(function(){
$("#tableControl").on("click","*[data-valid]", function(){
....
});
});
I haven't tested the above but something like that should work. Or, just re-wire the events on the buttons after the partial view is refreshed on the page.
Related
I have a controller in c# and inside the controller there is a save method. The save method saves/updates data that is submitted by submit button click and javascript. The problem is, if you click on the button multiple time, it should only process the very first click and rest of them should be identified as duplicate submit and should be discarded by controller. How to do this in c# mvc web application?
Disable the button after it's clicked. So it can just be clicked once.
Simple way
when button clicked disabled it then actived again after you got response result from ajax! u can also add loader that make ur web look so cool!
<button id="btnSend" onClick="send()">submit</button>
<script>
btnSend=document.getElementById("btnSend");
function send(){
btnSend.disabled=true;
//set disabled button here
$.ajax({ type: "GET",
url: "http://www.google.de",
async: false,
success : function(text)
{
btnSend.disabled=false;
//set active to button
// add your code here
},
fail : function(text)
{
btnSend.disabled=false;
//set active to button
// add your code here
}
});
}
</script>
I would also disable the button on the client side. But you could also check if the submitted data is different from the stored data. If no changes were made you could just return without further saving logic.
Should it be possible to just save the data once? Maybe a redirect to a different view after saving could be a possible solution in special cases.
I am trying to submit a hidden form whenever a page is loaded, for which I have created a function in my controller. My problem is that I don't want to leave the current view, but I can not redirect to the view I want to stay in either because that would create a constant loop of loading the page, calling my function when loading has finished and then redirecting again. Therefore, I wanted to call this function without redirecting to the previous view but without rendering a new view either, for which I was using the following:
$this->autoRender = false;
$this->layout = false;
$this->render(false);
Nevertheless, these lines do not seem to be working for me, as the action keeps being redirected to this function trying to render a non existing view instead of staying in the previous one. Due to this, I'd like to know if there is another alternative for being able to call one function in my controller but staying at the page I am at (not by redirecting because of the looping aspect). In case it helps, I am adding the code I have for this action:
This is the part of the view I want to stay rendered where I have the functionality related to the hidden form
<?= $this->Form->create('Save data', array('url'=>'/exportations/save_data/'.$id, 'enctype' => 'multipart/form-data', 'method' => 'post', 'id' => 'data'))?>
<input type="hidden" id="svgGraph" />
<div class="" id="cont" style="display:none;"></div>
<?=$this->Form->end()?>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
var chart = Highcharts.chart( // code to create graph
);
var svg = chart.getSVG();
$("#svg1").val(svg1);
});
$(document).ready(function () {
document.getElementById('data').submit();
});
</script>
This is my current controller '/exportations/save_data/' function:
public function save_data(){
$this->autoRender = false;
$this->layout = false;
$this->render(false);
if($this->request->is('post')) {
$data = $this->request->data;
$exportation = $this->Exportation->save($data);
}
return;
}
Currently, with this code, the data s succesfully stored, but the user ends up with an empty view, as the controller tries to render the save_data view.
If there is only 1 (or a few) actions that load this form, you can handle this within the action.
In controller action that renders form initially, check for post and data, do what you need to, then complete the rest of the action and finish rendering the view. You don't have to redirect on post.
This way on save success you can set a request data param, which can be reflected in the view, and if set, the JS doesn't "re-fire" the form.
The AJAX idea from #Greg Schmidt in terms of UX is a better solution, I would choose that over my suggestion any day. I only propose this if you don't want to use AJAX
I'm trying to make a button that when it's being a click, it will trigger a click for another button too but with a delay for each of them. For example, if the Main Button is clicked, the Sub Button 1 will trigger a click, then Sub Button 2 will be clicked after 2 seconds and the Sub Button 3 will be clicked after 4 seconds.
The real scenario is a customer can select up to 3 products, the 3 products will be added to a cart if they click the main button because the add to cart button of those 3 products will be clicked too as they click the main button. The products page has an Ajax. If I click the main button, sometimes only 1 or 2 product(s) are being added. I'm trying to delay a click for each button.
$(".main-button").on("click",function(){
$(".container .row").each(function(i){
$rowNum = $(this).attr("id","row-" + i);
$rowNum.find("button").trigger("click").delay(5000).text("clicked");
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="main-button">Main Button</button>
<div class="container">
<div class="row">
<button class="sub-button">Sub Button 1</button>
</div>
<div class="row">
<button class="sub-button">Sub Button 2</button>
</div>
<div class="row">
<button class="sub-button">Sub Button 3</button>
</div>
</div>
$(".main-button").on("click",function(){
myLoop ($(".container .row").children().length)
});
var i = 1;
function myLoop (count) {
setTimeout(function () {
$('.container :nth-child('+i+')').children('button').text("clicked")
if (i < count) {
i++
myLoop(count);
}
}, 1000)
}
Try demo -
https://jsfiddle.net/jijomonkmgm/oL3bzp5r/
This isn't specifically what you asked for, but the outcome of the functionality that you seek will be the same.
In the comments, others and myself, talked about how you could choose to call your sub button functions within the main function itself, without having the logic of a chained button clicking functionality.
Before you can do that, you need to make sure that all of your sub functions are within the global scope so that you can access them in your main function.
Example:
subButtonOneFunction() {
//do something
}
subButtonTwoFunction() {
//do something
}
subButtonThreeFunction() {
//do something
}
$(".main-button").on("click",function(){
$.ajax({
type: 'POST',
url: '/path/to/your_page.php',
data: {
data : dataVar,
moreData : moreDataVar
},
success: function (html) {
subButtonOneFunction();
subButtonTwoFunction();
subButtonThreeFunction();
//and so forth
}
})
});
The sub button functions in this example is within reach of the main function, and so you will be able to call the sub functions within the main function.
Not knowing if there is more to your main function, other than the delayed, button clicking loop that you were attempting, I tried to provide an example of how an AJAX function works, plus adding a success function where you can call your sub functions.
Firstly, we declare the type. The type is the data type for the data the AJAX function will parse. Notable data types are POST and GET.
Secondly, we declare the url. The url is the page where your data will be parsed to. It can be your current page, or another page entirely.
Thirdly, we declare our variable names for our data that we wish to parse, and what their content is. The variables go by the same logic as any other variables that you know from JavaScript. So they can contain numbers, strings, arrays, whatever you normally know.
Taking one of the data variables from the AJAX example and giving it a value could be done like this:
Our AJAX example: data : dataVar
Literal example: data : $('input#SomeInputContainingValue').val()
our AJAX variable data will now contain the value of an input field that has the id SomeInputContainingValue.
Another example using the clicked elements value: data : $(this).val()
As you can see, the data is simply variables that you would declare as any other JavaScript variable. The difference here is that : is basically the syntax for = in the AJAX function's data array.
Lastly, we declare our success function in the AJAX function. What this does, is that it allows us to "do something" upon success. This is where you can call your sub functions for instance.
This would be a much cleaner approach, and will be much easier to look through when going over the application in the future, and doesn't look like a "hack" or other workarounds.
I use Codeigniter and Bootstrap.
I have a button:
<a class="btn btn-success" id="btnid" href="http://site/controllerName/parameter">Text</a>
If I click to the button its call a controller with one parameter then the controller redirects to a site.
My question is that is there a way to call the controller with a parameter but skipping the redirection?
Try following
$(document).ready(function(){ // Add your event handlers inside ready block
$("#btnid").click(function(event) { // button event handler
event.preventDefault(); // prevent page from redirecting
$.ajax($(this).attr('href')).done(function(response) { // send call
// after call
});
});
});
For details refer to - ajax, preventDefault
Edit
As there are more than one link. You can use class selector. Currently, you have 2 classes btn and btn-success. You can use either of them, however, I will suggest you to add one more class let us say btn-api
Then update your click selector to
$(".btn-api").click(function(event)) {
event.preventDefault(); // prevent page from redirecting
$.ajax($(this).attr('href')).done(function(response) { // send call
// after call
});
});
https://api.jquery.com/event.preventdefault/ - prevents the default action
$( "a" ).click(function( event ) {
event.preventDefault();
}
You need to use event.preventDefault();
This is an exemple with just JavaScript (Not jQuery)
<script>
function stopDefAction(evt) {
evt.preventDefault();
}
document.getElementById('btnid').addEventListener(
'click', stopDefAction, false
);
</script>
You can find documentation and complete exemple here:
https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
You can call a javascript method which does a ajax call. Then there will be no redirect.
<a class="btn btn-success" id="btnid" onclick="javascript:theFunction();" href="#">Text</a>
<script type="text/javascript">
function theFunction () {
event.preventDefault();
// add your ajax call to the controller here e.g
$.ajax({
url: "http://site/controllerName/parameter"
}).done(function() {
// action when the controller call returns
});
}
</script>
By default a click on the a link to a controller will either render this controller's view or redirect to another view. To stop redirecting, you must call the controller via AJAX. To fully understand this, lets see what happens when you don't use ajax:
You click on the link which triggers the request.
The request is routed to your controller.
The controller processes the request. The ending line of the controller is something like $this->load->view('your-view');
This loads the raw HTML after any view logic has been processed and sends it back to your browser via normal HTTP. This issues a redirect (or a refresh if it was the same page).
What AJAX does, is that it takes the data received in step 4, and makes it available in a variable via javascript. To see this, we can write a code snippet:
HTML
<a onclick="getAjaxData()" class="btn btn-success" id="btnid">Text</a>
The easiest way to use ajax is via JQuery.
Javascript
function getAjaxData(e) {
// Make sure that the link default action doesnt occur.
e.preventDefault();
$.ajax({
type: 'GET', // depending on the controller method.
url: 'http://site/controllerName/parameter',
success: function(data)
{
// The variable data contains the data returned from the controller.
},
error: function()
{
alert('Something went wrong!');
}
});
Now if you leave things as they are, the vairable data will contain the raw HTML returned from the controller. Usually if you will use AJAX, it is better to either return HTML snippets which you can append directly to your current HTML DOM, or return data in JSON format, which you can then process via javascript.
I need to reload a page when clicking in a submit button. What the new page should show depends on the checkboxes selected previously to the reloading.
My problem is that, when I click "submit", $("button").click(function()... takes the correct values but $(document).ready(function ()... takes always the values true (which are selected as default).
How can I save those values before the reloading so that I can use them on $(document).ready(function ()...? Can I send them as data parameter
$(document).ready(function() {
var selectedCheckboxes = new Array();
$.ajax({
url: 'getNewForm.php?accion=value1',
data: 'selectedCheckboxes',
dataType: 'json',
error: function() {
alert("ERROR");
},
success: function(res) {
//Do something
}
}
});
$("button").click(function() {
var selectedCheckboxes = new Array();
selectedCheckboxes[0] = document.getElementById("checkbox1").checked;
selectedCheckboxes[1] = document.getElementById("checkbox1").checked;
});
});
Note: I did var selectedCheckboxes twice trying to get different results, donĀ“t know where I should do it.
You have several problems here:
You have a syntax error in your code sample. Make sure the code you post to StackOverflow compiles and runs without syntax errors (assuming you're not asking why a particular code snippet is generating syntax errors :) ).
The data attribute of your AJAX request is incorrectly specified as the literal string 'selectedCheckboxes', which means that your browser will send the literal string "selectedCheckboxes" as the payload to your server.
In addition, as you correctly surmise, you don't correctly handle the initialization of selectedCheckboxes. Variables initialized with var in JS are scoped to the containing function, which means the selectedCheckboxes declaration inside your click() handler are never going to be seen outside it.
Also, you're getting the value of "checkbox1" twice; you probably want to get something named "checkbox2" or similar. Related: If you are just serializing the only inputs in the form, use jquery's serialize() method so you have less code.
If you're really reloading the entire page anyway, don't use an AJAX request to do it? Using AJAX for form submissions is common when you do not want to reload the entire page (see below), but for your stated use case, it adds complexity you don't need. Just have a simple form with checkboxes and a submit button, and let the browser do it's default action.
Here's an example of using AJAX to submit a form behind the scenes, without reloading the entire page:
http://jsfiddle.net/Palpatim/rLeGv/
Given the HTML:
<form id="checkboxForm">
<input type="checkbox" name="check" value="check1" checked="checked" id="ch1"/>
<label for="ch1">check1</label>
<br/>
<input type="checkbox" name="check" value="check2" checked="checked" id="ch2" />
<label for="ch2">check2</label>
<br/>
<button>Click me</button>
</form>
This JS will submit a form when the button is clicked:
$(document).ready(function() {
$("button").click(function() {
$.ajax({
url: 'getNewForm.php?accion=value1',
data: $('#checkboxForm').serialize(),
dataType: 'json',
error: function() {
alert("ERROR");
},
success: function(res) {
alert("SUCCESS");
}
});
});
});
As far as loading a new page with the previous selections, you will have to maintain the state somehow. Your options include passing the state back from the server, storing the selections in the browser's local storage, or a cookie. I'd suggest passing the state back from the server, but your use case is a bit unclear.