MVC Partial View Returns Whole Page Instead of Just the Partial - ajax

I have the following partial view named "_transactions":
<div id="section-transactions" class="documentsanchor">
</div>
<div>
<div class="row">
<div class="col-lg-12">
<div>
<h4 class="company-headings">#ViewBag.SecSymbol Transactions</h4>
</div>
<div>
</div>
</div>
I render it using
#{Html.RenderAction("Transactions", "Company");}
and this is the Transactions method from the Company controller:
public async Task<PartialViewResult> Transactions()
{
ViewBag.SecSymbol = "test";
return PartialView("_transactions");
}
It's on a page with other partial views.
This works fine. However, I have a button on the page that should get a new partial view and replace the current one. It makes an ajax call as follows
$("#btn_transactions").click(function (e) {
var url = "Company/Transactions";
$.ajax({
url: url,
success: function (result) {
alert(result);
$('#transTarget').html(result);
},
error: function () {
alert("Error occured");
}
});
})
The issue is that the whole page is returned in "result", that is, all partials as well as the layout, when all I want is the transactions partial. What am I doing wrong?

Add this code in partial view
#{
Layout=null;
}

Make sure you have the route set up in your configs -
routes.MapRoute("CompanyTransactions", "company/transactions", new { controller = "Company", action = "Transactions" });

Related

ASP.NET Core 6 MVC ajax render view in Body Section

I am creating an ASP.NET Core 6 MVC application.
In my _Layout.cshtml I have a menu that the option calls a method in the controller that renders a View in #RenderBody()
Simplifying, the menu is like this
<li><a class="nav-link link-light" asp-controller="Employer" asp-action="Index">Employer Setup</a></li>
The controller is like this
public IActionResult Index()
{
var sessionValue = HttpContext.Session.GetString("Header");
HeaderViewModel header = JsonSerializer.Deserialize<HeaderViewModel>(sessionValue);
return View("Index", header);
}
Under certain circumstances, I also need to call this action by Ajax. I have define this in my _Layout.cshtml:
<div>
<main id="main" role="main" class="pb-3">
#RenderBody()
</main>
</div>
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$.ajax(
{
type:"POST",
url: '#Url.Action("Index", "Employer")',
success:function(result){
$("#main").html(result);
},
}
);
</script>
The problem I have is that the controller returns a view, so the entire layout is rendered again in the body section, instead of rendering only the new view. So I have to return a partial view instead of a view.
I do not want to duplicate the method to retrieve the same data.
Is there a way to return a view?
in view
<script type="text/jscript">
$(document).ready(function () {
$("#partialviews").load('/controller/actionmethod');
});
in controller
public PartialViewResult ActionMethod()
{
return PartialView("_partialviewname");
}
return View("Index", header);
Because you return view, so the the entire layout is rendered again in the body section.
You can create a new action to display the content.
HomeController:
public IActionResult Index()
{
return View();
}
public ContentResult TestData(string header)
{
header = "sss";
return Content(header, "text/plain");
}
Layout:
<div>
<main id="main" role="main" class="pb-3">
#RenderBody()
</main>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
$.ajax({
type: 'GET',
url: '/home/TestData/',
success: function (result) {
$('#main').html(result);
}
});
});
</script>
Result:

Form post from partial view to API

I am trying to create an SPA application using Sammy. When I call #/entitycreate link, I return a partial view from Home controller which contains an html form to submit. Partial view comes as I expect but rest of it doesn't work. Below are my problems and questions, I'd appreciate for any help.
KO binding doesn't work in partial view, even though I did exactly how it's done in the default SPA project template (see home.viewmodel.js).
This one is the most critical: when I submit this form to my API with ajax/post, my model always comes back with a null value, therefore I can't create an entity via my API. I have tried with [FromBody] and without, model always comes null.
In some sense a general question, should I include Html.AntiForgeryToken() in my form and [ValidateAntiForgeryToken] attribute in my API action?
Partial View:
#model namespace.SectorViewModel
<!-- ko with: sectorcreate -->
<div class="six wide column">
<div class="ui segments">
<div class="ui segment">
<h4 class="ui center aligned header">Create New Sector</h4>
</div>
<div class="ui secondary segment">
<form id="entity-create-form" class="ui form" action="#/sectorcreatepost" method="post" data-bind="submit: createEntity">
<!-- I am not sure if I should include AntiForgeryToken for WebAPI call -->
<!-- Html.AntiForgeryToken() -->
<fieldset>
<div class="field required">
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name, new { data_bind = "value: name" })
</div>
<div class="ui two buttons">
<button class="ui positive button" type="submit">Create</button>
<button class="ui button" type="button" id="operation-cancel">Cancel</button>
</div>
</fieldset>
</form>
</div>
</div>
</div>
<!-- /ko -->
JS View Model:
function SectorCreateViewModel(app, dataModel) {
var self = this;
self.name = ko.observable("ko binding doesn't work");
self.createEntity = function () {
console.log("ko binding doesn't work");
}
Sammy(function () {
this.get("#sectorcreateget", function () {
$.ajax({
url: "/home/getview",
type: "get",
data: { viewName: "sectorcreate" },
success: function (view) {
$("#main").html(view);
}
});
return false;
});
this.post("#/sectorcreatepost",
function () {
$.ajax({
url: "/api/sectors",
type: "post",
data: $("#entity-create-form").serialize(),
contentType: "application/json; charset=utf-8",
success: function (response) {
console.log(response);
},
error: function (xhr, status, error) {
console.log(xhr);
console.log(status);
}
});
return false;
});
this.get("#/yeni-sektor", function () {
this.app.runRoute("get", "#sectorcreateget");
});
});
return self;
}
app.addViewModel({
name: "SectorCreate",
bindingMemberName: "sectorcreate",
factory: SectorCreateViewModel
});
API Action:
public HttpResponseMessage Post([FromBody]SectorViewModel model)
{
// model is always null, with or without [FromBody]
if (!ModelState.IsValid)
return Request.CreateResponse(HttpStatusCode.BadRequest);
// repository operations...
return response;
}
I have removed contentType: "application/json; charset=utf-8", from ajax request based on the article here. #2 is now resolved, #1 and #3 still remains to be answered.

MVC: Can't make fancybox work

I am trying to update an existing application and wants to display modal using fancybox. On other functionalities, I was able to display the fancybox but for some reason cannot do it on a particular view.
Here is my main view declaration:
#Html.ActionLink(Strings.Link_ViewFullList, "OrganisationFullList", new { id = 1 }, new { #class = "fancybox fancybox.ajax" })
Then here is my "organisationFullList" cshtml file.
#model ProjectOrganisationModel
#{
ViewBag.Title = Strings.PageTitles_Organisations;
}
<div class="row">
<div class="col-lg-10">
#if (Model.Organisation != null && Model.Organisation.Any())
{
<ul class="list-unstyled">
#foreach (var organisation in Model.Organisation)
{
<li>
#Html.RadioButton("organisationList", organisation.Name)
#Html.Label(organisation.Name, new { style = "font-weight: normal" })
</li>
}
</ul>
}
</div>
</div>
Here is my controller code:
public ActionResult OrganisationFullList(int id)
{
var organisationList = new ProjectOrganisationModel();
organisationList.Organisation = GetOrganisations();
return View(organisationList);
}
When I click on the link, it displays a new screen instead of the modal. It redirects to this URl:
https://localhost:44300/project/1/organisationfulllist
#Html.ActionLink causes you to redirect to another page.
Rather than using #Html.ActionLink use #Ajax.ActionLink
#Ajax.ActionLink(
"View Full List Ajax",
"OrganisationFullList", //Action
"YourController", //Controller
new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "showFancyBox" //call back
}
)
Call back function:
function showFancyBox(data) {
$.fancybox.open({ "content": data });
}
Dont forget to include jquery.unobtrusive-ajax.min.js you need it to use #Ajax helpers
<script type="text/javascript" src="/Scripts/jquery.unobtrusive-ajax.min.js"></script>

Saving multiple partial views from one main page

Here is my requirement :
I am designing a page to add a vehicle to the database :
Normal vehicle information [Model - Inventory]
Some other features [Model - IList]
Here is my index.cshtml page
#model Model.ViewModel.VehicleViewModel
<div>
<div class='col-md-12'>
<div class="form-group">
<input id="mainFormSubmit" type="button" value="Save" class="btn btn-default" />
</div>
</div>
#{Html.RenderPartial("~/Views/Shared/_InventoryPartial.cshtml", Model.InventoryVM);}
#{Html.RenderPartial("~/Views/Shared/_StandardFeaturePartial.cshtml", Model.StandardFeatures);}
</div>
<script type="text/javascript">
$('#mainFormSubmit').click(function () {
$('#InventoryForm').submit();
$("#StandardFeatureForm").submit();
});
</script>
This is my view model class
public class VehicleViewModel
{
public InventoryViewModel InventoryVM { get; set; }
public IList<StandardFeature> StandardFeatures { get; set; }
}
The Inventory partial view [_InventoryPartial.cshtml]
#model Model.ViewModel.InventoryViewModel
#{
var options = new AjaxOptions() { HttpMethod = "Post" };
}
<div class="container">
<div class="row">
<div class="col-md-12">
#using (Ajax.BeginForm("InventorySave", "AddVehicle", options, new { id = "InventoryForm" }))
{
<fieldset>
<legend>Inventory Info</legend>
<div class='col-md-6'>
<!-- VIN input-->
<div class="form-group">
#Html.LabelFor(x => x.VIN, new { #class = "col-md-4 control-label" })
<div class="col-md-7">
#Html.TextBoxFor(x => x.VIN, new { #class = "form-control", #placeholder = "VIN" })
</div>
</div>
</div>
</fieldset>
}
The standard feature partial view [_StandardFeaturePartial.cshtml]
==
#model IEnumerable<Model.DomainModel.StandardFeature>
#{
var options = new AjaxOptions() { HttpMethod = "Post" };
}
<div class="container">
<div class="row">
<div class="col-md-12">
#using (Ajax.BeginForm("StandardFeatureSave", "AddVehicle", options, new { id = "StandardFeatureForm" }))
{
When I am clicking on index page SAVE button, only
$('#InventoryForm').submit();
$("#StandardFeatureForm").submit();
last one(StandardFeatureForm) is executing.
Please let me know if this process is correct, and what could be the reason of this issue.
You should not call the submit method twice. Depending of the browser you can face different issues :
the form submission causes the browser to navigate to the form action and the submission
of the first may prevent the submission of the second
The browser could detected there are two requests and discards the
first submit.
In your case it will be easier to wrap your two partial views inside a unique form.
#using (Ajax.BeginForm("InventorySave", "AddVehicle", FormMethod.Post, new { id = "InventoryForm" }))
{
#{Html.RenderPartial("~/Views/Shared/_InventoryPartial.cshtml", Model.InventoryVM);}
#{Html.RenderPartial("~/Views/Shared/_StandardFeaturePartial.cshtml", Model.StandardFeatures);}
}
However when the partial views render they are not generating the correct name attributes for the larger modelModel.ViewModel.VehicleViewModel you want to use :
public void InventorySave(VehicleViewModel vehicleViewModel) {}
In this case you should use EditorTempmlate instead of partial views. It's simple to do from your partial views and this post should help you :Post a form with multiple partial views
Basically, drag your partials to the folder ~/Shared/EditorTemplates/
and rename them to match the model name they are the editor templates
for.
Finally something like :
#model Model.ViewModel.VehicleViewModel
#using (Html.BeginForm("InventorySave", "AddVehicle", FormMethod.Post, new { id = "InventoryForm" }))
{
#Html.EditorFor(m => m.InventoryVM);
#Html.EditorFor(m => m.StandardFeatures});
}
The Ajax.BeginForm helper already has a submit event associated to it which creates an Ajax POST request. When you are manually submitting your form using $('#InventoryForm').submit();, you're calling both and the submit events which can have strange side effects.
There are a few ways around this. Here is one solution
Change your forms to a regular HTML form using the Html.BeingForm helper.
Amend your script to create ajax requests and use the form data
$('#InventoryForm').submit(function(e) {
e.preventDefault();
$.post($(this).attr("action"), $(this).serialize(), function(r) {
//Do something
});
});
$('#StandardFeatureForm').submit(function(e) {
e.preventDefault();
$.post($(this).attr("action"), $(this).serialize(), function(r) {
//Do something
});
});
Hope this helps

Refresh Partial view

I used #Html.RenderAction("_DisplayImages") to render a partial view.
#model List<Univems4.Models.ImageViewModel>
#foreach (var image in Model)
{
<div class="set">
<div class="header invisible">
<label class="edit">#image.Name</label>
<button class="close btnDeleteImage" title="Delete">×</button>
</div>
<img class="img-thumbnail edit" src="data:image/bmp;base64,#image.base64string" id="#image.Id" />
</div>
}
Upon button click, I want to refresh this partial view. The approach I tried is by using jQuery ajax get method.
$.get("/VmsMessage/_DisplayImages", null, function (data) {
//success
$('#bit').html(data);
}, "html");
The partial view was refreshed. but it no longer responds to the events. Why?
$(".set").hover(function (e) {
// do something
});
$(".edit").click(function (e) {
// do something
});
As the html will be genrated dynamically so events are not binded on DOM load you need to do event delegation:
$(document).on("mouseover",".set",function (e) {
// do something
});
$(document).on("click",".edit",function (e) {
// do something
});

Resources