Ajax UpdateTargedId / Browser doesn't refresh ASP MVC Partial View - ajax

I Have HTML Page "Index.cshtml"
<div class="container" >
<div class="row">
<div class="col-md-6" id="employeeList">
#Html.Partial("IndexPartial");
</div>
<div id="second">
other div
</div>
<button onclick="Increase()">increase</button>
</div>
</div>
partial view which contains employee table, button which clicked calls JS Script which executes controller method increasing employee age
<script>
function Increase(id) {
$.ajax({
url: 'Main/Increase',
data: { id: 5 },
UpdateTargetId:"employeeList",
success: function () {
alert('Added');
}
});
}
</script>
I ran firebug and it shows that each button click returns html response with updated employee Table (employee age is updated) but in browser there are still old values until I manually refresh page

You seem a bit confused. Let's go over a few things.
Partial is a built-in method that renders a view to a string (an IHtmlString). This runs once when the page is being constructed.
$.ajax() is a jQuery function. This function (as far as I can recall) does not accept a property called UpdateTargetId. I think you've confused that with the .NET AjaxOptions class which does accept an option called UpdateTargetId.
One way to quickly get things working is to change your success function to take a data argument and then insert the HTML into the div.
success: function (data, textStatus, xhr) { }

Related

Call Controller Method Which Return View With Ajax Call From Asp.net MVC View Page

i'm using .Net core 2.1 application, inside for loop how can i trigger controller view page without returning to ajax response,
see following code
this is my razor view
#foreach (var item in Model.CategoryList)
{
<div class="col-sm-6 col-md-4 mb-4 mb-lg-0 col-lg-2" onclick="SelectCategory(#item.CategoryId)">
<a href="#" class="popular-category h-100">
<span class="icon"><span class="#item.Icon"></span></span>
<span class="caption mb-2 d-block">#item.CategoryName</span>
<span class="number">32,891</span>
</a>
</div>
}
<script>
function SelectCategory(id) {
$.ajax({
type: 'POST',
url: '#Url.Action("ProductsList","Home")',
dataType: 'json',
data: { parentId: id }
});
}
</script>
public ActionResult ProductsList(int parentId)
{
List<PilCategory> all = new List<PilCategory>();
if(parentId > 0)
all = _context.PilCategory.Where(x=>x.ParentId == parentId).OrderBy(a => a.ParentId).ToList();
else
all = _context.PilCategory.OrderBy(a => a.ParentId).ToList();
return View(all);
}
pls someone help me, thaks for advance
how can i trigger controller view page without returning to ajax response
As far as I know, we couldn't trigger controller view page without returning to ajax response. Since the ajax will send the request to the controller view and the controller view will return the view as html response back to the ajax.
If we don't handle the response, that means current page will not change.
If you just want to pass the parentId to the ProductsList method, I suggest you could try to use window.location, this will make this page redirect to the ProductsList view which achieve refresh the whole page.
Notice: If we using ajax to call ProductsList, the whole page will not refresh. If we using window.location, it will redirect to another page or refresh the whole page.
More details about how to achieve this, you could refer to below codes:
#section Scripts{
<script>
function SelectCategory(id) {
location.href = "/Home/ProductsList?parentId=" + id;
}
</script>
}
If you want to use ajax to achieve this, I suggest you could try to handle the response by using ajax success method. Normally, we will return the partial view in controller method and then we could add it into the html page by using jquery without refreshing the page.
More details about how to achieve this, you could refer to this answer.

CORE 2 MVC Ajax redirect to display a view

I have an application that uses the jQuery Datatable and I want to click on a row, pick up the id, and then bring up a view that allows for editing of that view and updating the underlying database.
Ajax gets me to the controller-action that for the edit view but I can't get the view itself to display. Instead, the controller action just returns to ajax. I've tried numerous tactics with no joy. Here is a simple example based upon a standard CORE template:
#section scripts{
<script>
$(document).on('click', 'button.number', function () {
alert($(this).val());
$.ajax({
method: 'GET',
url: '#Url.Action("About", "Home")'
});
});
</script>
}
<h3>Home Page</h3>
<div>
<button href="#" type="button" class="number" id="one" value="1">1</button>
<button href="#" type="button" class="number" id="two" value="2">2</button>
</div>
Running the debugger shows that About action is called OK but the view isn't rendered - it just returns to ajax. I've tried all sorts of redirection but any "return" just goes back to ajax.
Is there away around this or perhaps a better way to get from the JS to the controller-action? Thanks
EDIT:
Batuhan gets the credit for his solution but I'm re-posting it to clean up a little syntax and add the parameter passing that was my initial goal.
$(document).on('click', 'button.number', function () {
var id = $(this).val();
alert(id);
$.ajax
({
method: 'GET',
url: '#Url.Action("About", "Home")',
}).success(function (result) {
window.location.href = '/home/about/' + id;
});
});
And here is Home Controller for the About Action:
public IActionResult About(int id)
{
string parm2 = id.ToString();
ViewBag.msg = parm2;
return View();
}
And the About page:
#{
ViewData["Title"] = "About";
}
<p>
<h1> #ViewBag.msg </h1>
</p>
All works as initially hoped for!
$(document).on('click', 'button.number', function () {
alert($(this).val());
$.ajax({
method: 'GET',
url: '#Url.Action("About", "Home")'
}).success: function(result){
///this line
window.href='redirect url';
}});;
});
this is a solution cause you cant redirect from ajax call. it returns The view in html form So if you want to postback you needto use window.href="url";

MVC correct handling of ajax search form and paging

I have a question regarding the ajax and simple filtering. Before writing this post i did read some question more or less regarding this topic, but it is not the same and i didn't receive my answere there!
I have a simple search page, with only few filtering, this filtering should not immidiately be adjustaed to the results or whatever. So when the user changes the filters and click search he gets the result, when he modifies filter nothing should happen until he clicks search again.
So my question is more about handling with the paging, i know how the paging works on the server side with .Skip() .Take() however when i click on the page number, i still have to do an ajax call and submit the same model back just with other page number, but the paging is outside of the form and it doesn't have submit stuff on it ... so how do i resubmit the model back with all the filteres in there?
So here is my view:
#using (Ajax.BeginForm("Index", "Search", new AjaxOptions { UpdateTargetId = "searchResults" }, new { #role = "form", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken();
#Html.EditorFor(m => m.IsOnline)
#Html.EditorFor(m => m.UserLocation)
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">#Base.Search</button>
</div>
</div>
}
And the paging is:
#if(Model.TotalPages>1)
{
<div class="row">
<div class="col-sm-12 col-centered">
<ul class="pagination text-center">
<li class="disabled">«</li>
#{
for(int i = 1; i<=Model.TotalPages; i++)
{
<li><a href="#">#i
#if(Model.CurrentPage==i)
{
<span class='sr-only'>(current)</span>
}
</a></li>
}
}
<li>»</li>
</ul>
</div>
</div>
}
And here is my controller:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Index(SearchModel searchModel)
{
if (ModelState.IsValid)
{
searchModel = Operations.GetSearchedListUsers(searchModel);
}
return View(searchModel);
}
So how i see it, even when i click on the page number i should do an index post action and re submit model but for example with other pagenumber how should i do it?
Or is my thinking is totaly wrong and in first place i shouldn't use ajax.form and model??
Please give advice?
Lets start with a general search page.
In search page we will a SearchPage view which have partial view SearchResult view which also may have another paging controls
SearchPage view will have all the control Filter that will keep the states if search, searchResult view update when Search Button is click. To maintain the filter,search keyword and page number and other states we would need to override the default submit and handle all through the ajax calls.
SearchResult view is partial view which will be updated on the searchbutton or Page click.
We might need to create searchModel model that has all the requires attributes:Filters,keyword and Page.
To make everything in ease, we would handle all these secenario in a single action called
Search with SearchModel. The searchModel will return a partialView("SearchResult").
Regarding the ajax call, lets say we have
var keyword=$("#txtKeyword").val();
var filter1=$("#txtFilter11").val();
function SubmitSearch() {
$.ajax({
url: '/Home/Search',
type: 'POST',
data: { keyword: keyword, Filter1: filter1}
timeout: 50000,
success: function (data) {
//Process data
},
error: function (x, t, m) {
if (t === "timeout") {
alert("got timeout");
} else {
alert(t);
}
}
});
}
And you can hook in the search button, page button etc.

Reloading main view after button in PartialView is clicked

I have a partial view that the user can preform a search in, and the search results are shown in a select box. In my main view I have a section that is supposed to show the search results after a select button is pressed. Right now when I click the select button is loads the correct information into the correct model for my main view, but the main view doesn't change. When I click refresh, the page updates correctly. How do I make the page update automatically when a button is clicked in the plugin view?
My section in the main view (Index.vbhtml) in my main app:
#Section CUInfo
Credit Union Name: #Model.CUInfo.CUName
end section
Here is my controller method in my Plugin:
Function ChangeCUInfo(strCUName As String) As ActionResult
m_hostApp.CUInfo.CUName = strCUName
m_hostApp.blnPluginRefreshButtonPressed = True
Return View("Index", m_hostApp)
End Function
I've tried to set a boolean value in the hostApp object and then in my main razor view call this function if it is true:
#code
If Model.blnPluginRefreshButtonPressed = True Then
#<script type="text/javascript">
$(function () {
window.location.reload();
});
</script>
End If
Model.blnPluginRefreshButtonPressed = False
End Code
EDIT:
JS function called when the select button is clicked:
function loadCU(CUInfo) {
strCU = CUInfo.split('|');
strCUName = strCU[0];
$.ajax({
type: "POST",
url: "/CUContractNumberPlugin/ChangeCUInfo",
data: { "strCUName": strCUName }
});
}
Form that is used in the plugin view:
#Using (Html.BeginForm("ChangeCUInfo", "CUContractNumberPlugin"))
#<div id="LogoSigSearch" style="height:300px;width:500px;position:relative;">
<span style="display:inline-block;height:20px;width:166px;position:absolute;top:35px;left:5px;">Credit Union Name</span>
<br />
#Html.TextBox("strCUName")
<input type="submit" name="LogoSigSearch$ctl02" value="Search" id="LogoSigSearch_ctl02" tabindex="3" style="width:60px;position:absolute;top:5px;left:352px;" />
<input name="LogoSigSearch$ctl05" type="button" onclick="javascript:clearSearch()" value="Clear" style="position:absolute;top:35px;left:352px;width:60px;" />
<select size="4" name="LogoSigSearch$ctl06" id="LogoSigSearch_ctl06" tabindex="5" style="height:230px;width:342px;position:absolute;top:65px;left:5px;"></select>
<input type="button" name="SelectCU" value="Select" onclick="javascript:loadCU(LogoSigSearch_ctl06.options[LogoSigSearch_ctl06.selectedIndex].value)" tabindex="4" style="width:60px;position:absolute;top:65px;left:352px;" />
</div>
End Using
Are both buttons part of a form? A button won't invoke an action without you attaching it to script or making it part of a form with an associated action.
Use a partial view to render the results of the query, even on the main page load. This simplifies your development.
Add a jQuery event handler (jQuery.on()) to watch for the button click on your main page, or if the button is returned in the partial view, just use an on ready handler in your partial and attach a button.click() event, again using jQuery.
The jQuery event handler can take care of submitting the values of the query, posting to your controller, and displaying the results. I have a number of older articles here but they are still relevant to your question and demonstrate submitting data and fetching partials.
Your client-side code will end up looking something like this:
$("#your-button").click(function () {
var fetchUrl = '#Url.Action("ActionName", "Controller")';
$.post(fetchUrl, { searchParams: $("#your-search-box").val() })
.success(function (data) {
// replace the contents of the DIV with the results. 'data'
// here has whatever you sent back from your partial view
})
.error(function (data) {
// handle the error, use a DIV with some kind of alert message etc
});
});
Hope this helps some.

MVC 3 Razor #Html.ValidationMessageFor not working in partial loaded via jquery.load()

I have put together a small example here just to replicate the problem.
I have a strongly typed partial view _Name.cshtml:
#model ValidationInPartial.ViewModels.MyViewModel
<h2>#ViewBag.Message</h2>
<fieldset>
<legend>Name</legend>
<div class="editor-label">
#Html.LabelFor(model => model.MyName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MyName)
#Html.ValidationMessageFor(model => model.MyName)
</div>
Reload Name
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<script type="text/javascript">
$(document).ready(function () {
$("#reload").click(function () {
$("#divName").load("Home/NameReload");
});
});
</script>
that is initially loaded and displayed inside the main Index.cshtml
<div id="divForm">
#using (Html.BeginForm()) {
<div id="divName">
#Html.Partial("_Name")
</div>
}
</div>
The field MyName is required and validation is implemented through Required attribute in MyViewModel
namespace ValidationInPartial.ViewModels
{
public class MyViewModel
{
[Required(ErrorMessage = "Please enter a Name.")]
public string MyName { get; set; }
}
}
After the page is loaded the first time, if you click the Create button leaving the field empty the validation message "Please enter a Name." shows beside the field and the field itself turns pink, which is the expected behaviour.
Now by clicking the "Reload Name" link, which makes an ajax call (jquery.load(...)), the partial is reloaded, here is controller code:
public PartialViewResult NameReload()
{
MyViewModel myViewModel = new MyViewModel();
ViewBag.Message = "Name Reloaded";
return PartialView("_Name", myViewModel);
}
This time if you click the Create button leaving the field empty the validation message does not appear beside the field, although the field turns pink.
It turns out that when reloading the partial the #Html.ValidationMessageFor doesn't render the validation message as the first time.
Here is the jquery files I use
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
I wonder if this is a bug in the way the Razor engine renders the #Html.ValidationMessageFor or is that a problem with jquery?
Any idea why this happens?
I have also read somewhere that the ajax call looses all the scripts for the page, in fact I have to keep any javascript code inside the partial so that they can be rendered and used again.
In the meantime I found a workaround which is to manually render in the partial what was supposed to be rendered by #Html.ValidationMessageFor which is:
<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="MyName"></span>
However this workaround means that if we change the type of validation or just the validation message inside the Required attribute in the ViewModel, we need to modify this hard-coded piece of html in the view.
#NickBork has a great answer here. The key is that ASP.NET's MVC rendering engine does not output the validation script if it doesn't think that there is a form. The example given hacks it buy putting in a form and then selection an inner section of HTML from was was returned, essentially throwing the outer wrapper of the form away.
There is another method so that you can just get your view:
ViewContext.FormContext = new FormContext();
With this method, there won't actually be FORM code output, but the validation markup will be there.
Thanks,
John
Validation markup (span tags, custom field attributes, etc) are not rendered unless your fields are contained within a FORM. The validation plugin itself does not work with elements outside of a form.
When ASP.NET renders your Partial View the controls are not within a form and thus do not get the elements rendered.
When you load you're partial content you'll need to parse the HTML using a jQuery selector.
In my sample below I have a TBODY on the parent View page that contains rows. When I need to add additional rows, I make a call to a View which had a form, table, tbody and collection of rows.
$.ajax({
type: "POST",
url: "/controller/action",
data: ({Your: 'dataHere'}),
dataType: "html",
success:
function(response){
$('tbody').append($('tbody',$(response)).html());
//The validation plugin can't bind to the same form twice.
//We need to remove existing validators
$('form').removeData("validator");
//Refresh the validators
$.validator.unobtrusive.parse(document);
},
error:
function(){
alert('An error occured while attempting to add the new content');
}
});
Note that I'm using a jQuery selector to select the rows that are inside of the View/PartialView that are loaded in by using AJAX:
$('tbody',$(response)).html()
The rest of the wrapper just appends the rows from the AJAX View/PartialView to the calling parents tbody:
$('tbody').append($('tbody',$(response)).html());
A couple other notes, after the validator plugin has been run on a form, it can not be called again without re-adding it (see jquery.validate.unobtrusive not working with dynamic injected elements)
To fix this, I first call the following method to remove all validators:
$('form').removeData("validator");
$("form").removeData("unobtrusiveValidation");
I then refresh the validators using the following:
$.validator.unobtrusive.parse(document);
I can't remember where I found the solution. The reason is because you are loading a PartialView into a View that has already been parsed by the jquery.validator.unobtrusive library. You need to re-parse the unobtrusive library
function ReparseValidation(){
jQuery.validator.unobtrusive.parse("#yourcontainer");
}

Resources