PartialView not rendering properly on ajax reload - c#

Im having an issue to reload a partial view using ajax.
I have my country form in a partial view, and initially when i load the main page everything is rendered properly.
As demonstrated in the image below, I can search for country using my autocomplete and i can select a countryfrom my combobox (both are kendo-mvc controntrols)
The issue emerges when i select a from my autocomplete and try to load the info of the selected country via ajax. The form is reloaded, the info is displayed but the controls are not being rendered properly. The autocomplete stops working and the combobox is rendered as a normal textbox, displaying the CountryID instead of the Country name.
Code in my view
#using (Html.BeginForm("Index", "CountryManagement", FormMethod.Post, new { id = "country-form" }))
{
#Html.ValidationSummary(true);
<div id="form-content">
#Html.Partial("_CountryForm", Model)
</div>
}
Code in my partialview
<div class="form-group">
#Html.Label("Search Country", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-3">
#(Html.Kendo().AutoCompleteFor(m => m.Search)
.DataTextField("Designation")
//.DataValueField("CountryID")
.Filter("contains")
.MinLength(2)
.DataSource(d => { d.Read(r => r.Action("SearchCountry", "Common")); })
.Events(e => e.Change("onChange")).Deferred()
)
</div>
</div>
Code in my controller
[HttpPost]
public PartialViewResult Edit(int id)
{
//HTTP GET: api/Country/CountryDetails?id={id}&lang={lang}
dynamic model = //code to get selcted country data
return PartialView("_CountryForm", model);
}
Code in my .js file
function onChange() {
if ($("#Search").data("handler")) {
var data = $("#Search").data("handler").dataSource.data();
var country = data.find(x => x.Designation == $("#Search").val());
console.log("Country")
if (country) {
var request = $.post('/CountryManagement/Edit', { id: country.CountryID });
request.success(function (data) {
$("#form-content").html(data);
});
}
}
}
HTML code generated on page load (autocomplete and dropdown only)
<div class="form-group">
<label class="control-label col-md-2" for="Search_Country">Search Country</label>
<div class="col-md-3">
<span tabindex="-1" role="presentation" class="k-widget k-autocomplete k-header k-state-default k-state-hover"><input data-val="true" data-val-length="Description must have between 1 and 150 characters" data-val-length-max="150" data-val-length-min="1" id="Search" name="Search" type="text" data-role="autocomplete" class="k-input" autocomplete="off" role="textbox" aria-haspopup="true" aria-disabled="false" aria-readonly="false" aria-owns="Search_listbox" aria-autocomplete="list" has-focus="false" style="width: 100%;"><span class="k-icon k-loading" style="display:none"></span></span>
</div>
</div>
<br>
<br>
<div class="form-group">
<label class="control-label col-md-2" for="Country">Country</label>
<div class="col-md-3">
<span class="k-widget k-combobox k-header"><span tabindex="-1" unselectable="on" class="k-dropdown-wrap k-state-default"><input name="CountryID_input" class="k-input" type="text" autocomplete="off" title="" role="combobox" aria-expanded="false" tabindex="0" aria-disabled="false" aria-readonly="false" aria-autocomplete="list" aria-owns="CountryID_listbox" has-focus="false" style="width: 100%;"><span tabindex="-1" unselectable="on" class="k-select"><span unselectable="on" class="k-icon k-i-arrow-s" role="button" tabindex="-1" aria-controls="CountryID_listbox">select</span></span></span><input data-val="true" data-val-number="The field CountryID must be a number." id="CountryID" name="CountryID" type="text" value="0" data-role="combobox" aria-disabled="false" aria-readonly="false" has-focus="false" style="display: none;"></span>
<span class="field-validation-valid text-danger" data-valmsg-for="CountryID" data-valmsg-replace="true"></span>
</div>
</div>
HTML code generated on partialview reload (autocomplete and dropdown only)
<div class="form-group">
<label class="control-label col-md-2" for="Search_Country">Search Country</label>
<div class="col-md-3">
<input data-val="true" data-val-length="Description must have between 1 and 150 characters" data-val-length-max="150" data-val-length-min="1" id="Search" name="Search" type="text" value="South Africa">
</div>
</div>
<br>
<br>
<div class="form-group">
<label class="control-label col-md-2" for="Country">Country</label>
<div class="col-md-3">
<input data-val="true" data-val-number="The field CountryID must be a number." id="CountryID" name="CountryID" type="text" value="1003">
<span class="field-validation-valid text-danger" data-valmsg-for="CountryID" data-valmsg-replace="true"></span>
</div>
</div>
I'm not sure if this is an issue with ASP.Net MVC partialviews, Kendo controls or some scripts that should be re-run when the partialview reloads.
Can someone please help me?

After numerous failed attempts and fruitsless digging in the deep end of Telerik forums, i finally found out what the problem is.
Kendo widgets in partial views should not use deferred initialization.
#(Html.Kendo().AutoCompleteFor(m => m.Search)
///.. code removed to reduce complexity
.Events(e => e.Change("onChange")).Deferred()
)
When the view is loaded through as server request, it renders properly because in the end of the layout file, all the widgets with deferred initialization are initialized using #Html.Kendo().DeferredScripts(). However when the partial view is reloaded via ajax, the deferred scripts initialization never happens because the scripts are not re-run.
Adding #Html.Kendo().DeferredScripts() to the partial view solves the problem of ajax reload but becomes and issue on server loading because: 1 - The deferred initialization would be running twice, and 2 - Because kendo widgets have jquery dependencies and would be running before the jquery scripts are included in the page.
The solution i found was to not deffer the initialization of the widgets, however this would take us back to the point above regarding the jquery dependencies. And as much as i tried to avoid it, the only thing that really worked was to include jquery in the page header. All of the other scripts (validation, kendo, custom, etc) are still at the bottom but the main jquery script is at the top. And now my partial views load perfectly on server or ajax request.
TL;DR;
Do not use deferred initialization in partial views
Move jquery.min.js to the top of the page.
Hopefully there is a better way to do it but for now it does the trick.

So I was searching the forums and couldn't find a suitable fix either. But i did the following and it seems to work just fine. Basically if the partial is rendered normally then the layout view handles the deferred scripts, but if the request is through AJAX then the partial view will go ahead and render them.
I put this at the bottom of my partial:
#if (Context.Request.IsAjaxRequest())
{
<div id="kendo-scripts">
#Html.Kendo().DeferredScripts()
</div>
}
FYI, leave the .Deffered() at the end of your kendo object also in case that wasn't apparent.

Check for any page script initialization errors!
I was running into the same problem here and burned 3 days on it, the issue for me ended up being there was a page initialization script script around the no MutationObserver not being available in older safari browser. After adding a polyfill and fixing init error, dynamically injected ajax content with Kendo controls worked fine with no defer needed. Hopefully this saves someone else some frustration.
This init error affected jquery's ready initializer callback for any ajax content which Telerik relies upon to render each control in the script block that it emits.

Related

Format ASP .Net Input Tag Helper

Using ASP .Net Core (Version 2.2, NON-MVC)
I have a database field (Car) which contains text, in HTML format.
I am using an ASP .Net "Input" Helper Tag to display the data (read only) on a webpage.
<input asp-for="Car.Description" asp-format="" disabled class="form-control" />
I would like to display the data as Html.Raw, but am unsure how to do so.
I originally thought I could do something like this (use Html.Raw), but this throws an exception:
<input asp-for=#Html.Raw(Car.Description) asp-format="" disabled class="form-control" />
I then thought the "asp-format" field might have some usable options, but I don't see any.
<div class="form-group row">
<div class="col-2">
<label asp-for="Car.Description"></label>
</div>
<div class="col-10">
<input asp-for="Car.Description" asp-format="" disabled class="form-control" />
</div>
</div>
End result is that I would like to have the display "raw" HTML on the screen.
Thanks
If you want to display the field as read only, you may not even need the "input" helper tag. Just displaying the data in the div should work.
Remove the input helper and just display the text in the div as follows:
<div class="form-group row">
<div class="col-2">
<label asp-for="Car.Description"></label>
</div>
<div class="col-10">
#Html.Raw(Car.Description)
</div>
</div>

ASP.NET Razor Pages Error: InvalidOperationException: Incorrect Content-Type

So I'm relatively new to ASP.NET Razor and I'm getting a consistent error that I'm not sure how to fix. I've created an ASP.NET Core Web Application MVC with Razor Pages.
I'm currently getting the error: InvalidOperationException: Incorrect Content-Type: Microsoft.AspNetCore.Http.Features.FormFeature.ReadForm()
when I load the project. It's telling me that the error is in the line email = Request.Form["email];
File the error is relating to:
#page
#model IndexModel
#{
ViewData["Title"] = "Login";
var email = "";
var pswd = "";
bool rem = false;
email = Request.Form["email"];
pswd = Request.Form["pswd"];
}
<div class="progress mt-5">
<div class="progress-bar progress-bar-striped progress-bar-animated"
style="width:40%"></div>
</div>
<br />
<div class="container mx-auto bg-warning" style="width:50%;">
<h1 class="title" style="text-align:center">TestWebApp</h1>
<form method="post" class="px-3 py-5">
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text bg-primary border-0 text-light" style="width:100px">Email</span>
</div>
<input type="email" class="form-control" id="email" placeholder="Enter email" name="email" value="">
</div>
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text bg-primary border-0 text-light" style="width:100px">Password</span>
</div>
<input type="password" class="form-control" placeholder="Enter password" name="pswd" value="#pswd">
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="remember" value="#rem"> Remember me
</label>
</div>
<button type="submit" class="btn btn-primary" name="submit">Submit</button>
</form>
</div>
The weird thing is I ran this code multiple times before, just making small design changes with no relation to the form itself and it worked fine without an error but has now started showing this error and I'm not sure how to fix it. Would be very thankful for some help.
I don't know what does Request stand for in your code. Because nothing in your page is named that way. If you have some sort of shortcut somewhere I guess you're getting the Request property from your model. So you're referring to the PageModel's Request property that gets exposed because your model IndexModel inherits from PageModel.
If the aforementioned is true, then I suspect you're using the Request.Form in the wrong place here.
What are you trying to accomplish reading Request.From at that point in time, i.e - when the razor engine parses and renders your template? Please note, there's no form there yet. So that's probably why you're getting such error.
The error could be misleading because your code is messing with the request too early in the process. You're basically forcing the engine to read the form when nothing is there and the exception that pops out is telling you that the form doesn't have, neither application/x-www-form-urlencoded nor multipart/form-data as its Content-Type header value. But again, the main reason for the failure is that you're using the Request.Form in the wrong place.
Perhaps you should explain better what your final goal is, so we can get a better idea of what can be wrong?
Hope this helps!

Sitefinity Widget Designer not saving values

Created a custom widget in Sitefinity MVC, with a custom widget designer:
<div class="form-group">
<label for="My Field">My Field</label>
<div class="row">
<div class="col-xs-3">
<input type="text" sf-model="properties.MyField.PropertyValue" class="form-control" id="MyField" />
</div>
</div>
</div>
Defined in both the controller and the model:
public string MyField { get; set; }
When I click edit, the field shows up as expected. I click save, and then hit edit again: value not stored. Does not help to refresh the page, and is not showing up in the widget itself either.
Am I missing a piece? The documentation is a little long-winded and scattered, I've been scouring through it but nothing is jumping out at me.
I see a put request sent in dev tools, but the request payload is empty. Not sure if this is the right request or relevant.
sf-model should be ng-model
<div class="form-group">
<label for="My Field">My Field</label>
<div class="row">
<div class="col-xs-3">
<input type="text" ng-model="properties.MyField.PropertyValue" class="form-control" id="MyField" />
</div>
</div>
</div>

No data binding on form submission

I'm migrating a ASP.NET 5 app to ASP.NET core. Everything is going well except that I can't submit a form.
When I do, looking at the Chrome's network timeline, the controller URL is reached (/MyController/Create) but nothing happens (The browser is idling, waiting).
After looking for some explanations: trying to call a parameterless controller works fine. Adding [FromForm] returns a 415. [FromData] idle too...
I can't find anything on the internet. Here too! (For the first time during my entire life).
NB: Everything was working fine using ASP.NET 5 MVC 6. Same code on both side.
Here is my controller code:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(SocieteGroupe societeGroupe)
{
if (ModelState.IsValid)
{
_context.SocieteGroupe.Add(societeGroupe);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewData["Id_Devise"] = new SelectList(_context.Devise, "Id", "Code_ISO", societeGroupe.Id_Devise);
return View(PackageUtils.GetViewPath(viewPath, OperationType.CREATE), societeGroupe);
}
And my view :
<form asp-controller="SocieteGroupes" asp-action="Create">
<div class="form-horizontal">
<h4>SocieteGroupe</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Id_Devise" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="Id_Devise" class ="form-control" asp-items="ViewBag.Id_Devise"></select>
</div>
</div>
<div class="form-group">
<label asp-for="Id_Salesforce" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Id_Salesforce" class="form-control" />
<span asp-validation-for="Id_Salesforce" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Nom" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Nom" class="form-control" />
<span asp-validation-for="Nom" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
Does someone already faced out this problem or got an idea about it?
EDIT:
Instead of using a complexe type as parameter. I tried (for debug purposes) to use a string instead and return the string in Json format in order to debug it. Whatever I use (nothing, [FromForm], [FromBody]...), the result is null. I don't know what to do next. Any help will be appreciated :D
Thanks in advance :)
I found a workaround. This is a known bug of RC2.
According this link, you need to download this file and put it wherever you want in your project. Then you just need, in Startup.cs to add the line services.AddSingleton<IModelBinderFactory, MyModelBinderFactory>();
And that's all! For me, it worked :D

C# AJAX Comments in post

Here I made a simple webpage to post pictures, text, etc. I also made a simple ajax file to send the text, picture, etc to the database, and retrieve that information to be displayed in the same webpage. Here is the main webpage:
<div class="here" id="here">
#foreach (var photo in db.Query(photos, galleryInfo)){
<div class="com_1 com_3">
<div class="com_4">
<div class="com_44">
<img alt="miniatura" style="margin-top: 0" src="#Href("~/Photo/Thumbnail2", photo.UserId, new { size="small" })" class="thumbnail-border thumb22" />
<div class="n-s">
<b>#photo.Nombre #photo.Apellido</b>
</div>
</div>
<div class="com_5">
#photo.Comment
</div>
</div>
<div class="comcom">
<div class="comcom1">
<form onsubmit="return fofon(this)" id="gog">
<input type="text" style="display: none" name="GroupId" value="#galleryInfo" />
<textarea class="texta"name="comment" placeholder="Write a comment..."></textarea>
<input type="submit" class="g_sub"/>
</form>
</div>
</div>
</div>
}
In case it gets confuse, this shows every post with a "comment section" below each one (we can call them "Commne2"). The ajax will get the text, picture etc, send it to the database, and post it to another file, which will be displayed here... in the #foreach{}.
Obviously, the posts do not "excist", so any javascript that affects that post, will not work, because that element does not exciste in this case.
So my problem is, how can I create an ajax file (javascript file) that affects the Comment2 so that I can comment a post?

Categories