#Html.RenderAction with Ajax Form ASP.NET Mvc3 c# - c#

I have a scenario where i need some code setup when a control renders. I have a widget that'll be used on a number of pages called a QuickRate:
I'm trying to call it like so in my cshtml file:
<div class="dragbox" id="quick-rate">
<h2>Retrieve a Quick Rate</h2>
#Html.Action("Create", "QuickRate")
</div>
and then in the create on the QuickRateController.cs I have:
public ActionResult Create()
{
var model = new QuickRateModel();
model.Products = currentUser.GetProducts(dataRepository).ToSelectList(p => p.ProductId, p => p.ProductName);
return View("QuickRateResult", model);
}
i then have a QuickRatePartial.cshtml file that contains the following:
#model Project.Web.Models.QuickRateModel
#{
Layout = "";
AjaxOptions options = new AjaxOptions()
{
HttpMethod = "Post",
UpdateTargetId = "quick-rate-content"
};
}
<div class="clearfix">
#using (Ajax.BeginForm("GetQuickRate", "QuickRate", null, options, new { #id="quick-rate-form" }))
{
<fieldset>
#Html.DropDownListFor(model => model.ProductId, Model.Products)
#Html.ValidationMessageFor(model => model.ProductId)
<select data-val="true" name="DropDown1" data-bind="
options: Items1,
optionsText :'ItemName',
value: SelectedName
">
</select>
<select data-val="true" name="DropDown2" id="DropDown2" data-val-required="Please select an Item." data-bind="
options: SelectedItem().MoreItems,
optionsText: 'Text',
optionsValue: 'Text',
value: MoreItem,
optionsCaption: 'Select One'
"></select>
<div class="clearfix">
#Html.ValidationMessageFor(model => model.MoreItems)
</div>
<div>
<input type="submit" value="Get Quick Rate" />
</div>
<div id="quick-rate-content"></div>
</fieldset>
}
</div>
try as i might I can't get the form to render at all.. just wondering if you had any suggestions?
Cheers!

You've named the file quickratepartial.cshtml but in the action you are looking for a view called quickrateresult. Is this correct?

Related

Submit form over a select element in ASP.Net MVC

So in my file i have this working example of submitting a form and initiating a controller action. And in this form there is a functioning select element and it works as expected, the controller is able to retrieve the value in the select element.
#using (Html.BeginForm("InsertEntry", "Modeliai"))
{
<div class="row">
<div class="col-7">
<input type="text" class="form-control" placeholder="Pavadinimas" name="Pavadinimas">
</div>
<div class="col-3">
<select class="selectpicker" data-live-search="true" name="fk_MARKEid">
#foreach (var item in Model.Markes)
{
<option data-tokens="#item.pavadinimas" data-content="#item.pavadinimas">#item.id</option>
}
</select>
</div>
<button type="submit" class="btn btn-success">Add</button>
</div>
}
But when i try to add select element in the table row, controller somehow doesn't catch the value of the select element.
#using (Html.BeginForm("UpdateEntry", "Modeliai"))
{
<td>
<input type="hidden" name="id" value="#item.id" />
<input type="text" name="pavadinimas" class="form-control" value="#item.pavadinimas" />
</td>
<td>
<select class="selectpicker" data-live-search="true" name="fk_MARKEid">
#{
var ignore = Model.Markes.FirstOrDefault(x => x.id == item.fk_MARKEid);
}
#foreach (var x in Model.Markes)
{
if (ignore?.id == x.id)
{
<option data-tokens="#ignore?.pavadinimas" data-content="#ignore?.pavadinimas" selected="selected">#ignore?.id</option>
}
<option data-tokens="#x.pavadinimas" data-content="#x.pavadinimas">#x.id</option>
}
</select>
</td>
<td style="width: 100px">
<button class="close" type="submit">
<i class="fas fa-pencil-alt" style="font-size: smaller"></i>
</button>
</td>
}
Yes i tried checking if select element names and model names match.
Any help regarding making the second form work or explanation why does this happen would be appreciated
The better way to use select in ASP.Net MVC is to use #Html.DropDownListFor with SelectList.
Example: View
#Html.DropDownListFor(x => x.YourModel, new SelectList(ViewBag.customValue, "Text", "Value"), new { htmlAttributes = new { #class = "form-control" } })
Example: Controller
List<SelectListItem> listForSelect = new List<SelectListItem>();
listForSelect.Add(new SelectListItem { Text = "Your text", Value = "Your value" });
ViewBag.customValue = listForSelect;

c# mvc form: how to build view for simple feedback form leveraging the benefit of using html.editorfor?

I have simple input form (basically for feedback) with following fields:
Name, Gender, Mobile-Number, Complaint text. (To simplify I am not mentioning any POST action OR submit button on the form)
Currently, I have created following MVC structure:
public class ComplaintController
{
[HttpGet]
public ActionResult Index()
{
return View(); //This view displays the complaint form with all above fields
}
}
I read this and several other links where they suggest to use #Html.EditorFor as it creates UI based on model data-type.
Currently, I am not passing any model to the [HttpGet] view. If I want to use #Html.EditorFor, I need to pass my model to [HttpGet] Index View, how can I do that? What is best pratise to create such MVC forms?
Your Controller:
public ActionResult Index()
{
whateverModel d = new whateverModel();
return View(d);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(whateverModel m)
{
if (ModelState.IsValid)
{
//its valid, update your database or do soemthing useful here
return RedirectToAction("Success");
}
//its not valid reload the page and let data annotations show the error
return View(m);
}
Once you have your code in the controller then you can have visual studio auto-create your view. In your controller, right click the "d" in return View(d); and select "Add View." Change the Template to "create" and Model class to your Model (whateverModel in this example). It will auto generate the chtml page for you with the model imported and the editors already generated for you. Example auto generated view below. The you can work on styling and such.
cshtml:
#model YourSolution.Models.whateverModel
#{
ViewBag.Title = "Whatever";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Whatever</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Whatever</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.FriendlyName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FriendlyName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.FriendlyName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Order, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Order, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Order, "", new { #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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Currently, I am not passing any model to the [HttpGet] view. If I want
to use #Html.EditorFor, I need to pass my model to [HttpGet] Index
View, how can I do that?
Hi sahil ,As a first step , create one model class like below
public class FeedBack
{
public string Name{get;set;}
public string Gender{get;set;}
public int Mobile-Number{get;set;}
public string Complaint{get;set;}
// other additional fields
}
And in the controller get method ,pass a model like below
public class ComplaintController
{
[HttpGet]
public ActionResult Index()
{
FeedBack OBJFeedback = new FeedBack();
return View(OBJFeedback);
}
}
And in a view , strongly type this model and post the data as you want to the controller post methods.
Here is the example of strongly typed view : http://www.c-sharpcorner.com/UploadFile/abhikumarvatsa/strongly-typed-views-in-mvc/
Important Note : In the get action method , since you dont want to display any values by default in the view , even if you dont pass model object it will work in the same way.
Hope the above information was useful
Thanks
Karthik
If you want to use #Html.EditorFor, then you mast pass the model to the view.What does #Html.EditorFor do? It makes the html tag like
<input class="text-box single-line" id="Name" name="Name" type="text" value="">
So if you do not want to pass the model to the view then you need to write the raw html tag like above. It is important to keep the html tag's name property same as the mvc's model property because when you want to post the data to the controller the name property of the html tag will map the mvc model property and get the corresponding value at the Controller method.
At the view(somthing.cshtml) you can use html tags, because .cshtml==.cs+html . So the whole code look like
Controller methods
public ActionResult FeedBack()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult FeedBack(FeedBackModel Model)
{
var feedBack = Model;
return View();
}
And the View
<form action="/Home/FeedBack" method="post" id="feedBackForm">
#Html.AntiForgeryToken()
<hr>
<div class="form-group">
<div class="col-md-5">
<label for="Name">Name</label>
</div>
<div class="col-md-5">
<input class="text-box single-line" name="Name" type="text">
</div>
</div>
<div class="form-group">
<div class="col-md-5">
<label for="Name">Gender</label>
</div>
<div class="col-md-5">
<select name="Gender">
<option value="male">Male</option>
<option value="female">Female</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-md-5">
<label for="Name">MobileNumber</label>
</div>
<div class="col-md-5">
<input class="text-box single-line" name="MobileNumber" type="text">
</div>
</div>
<div class="form-group">
<div class="col-md-5">
<label for="Name">Complaint</label>
</div>
<div class="col-md-5">
<textarea class="text-box single-line" name="Complaint"></textarea>
</div>
</div>
<div class="col-md-5">
<input type="submit" value="Create" class="btn btn-default">
</div>
</form>
If you do not want to use submit then you can use ajax.

#Html.DropDownList return null to controller

The DropDownList in my view shows the relevant options to choose, but no matter what i choose, the folders in the Controller get value null.
Why? How can i fix it so the folders in the Controller will get the chosen option from the DropDownList from the view?
P.S - I have no Model.
This is my Controller:
//POST: Home
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(IEnumerable<HttpPostedFileBase> file, string folder, IEnumerable<SelectListItem> folders)
{
// some code here
}
This is my view:
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken();
<div class="container">
<div class="form-horizontal">
<div class="form-group">
<p></p>
<label for="file">Upload Photo:</label>
<input type="file" name="file" id="file" accept="image/*" multiple="multiple"/>
</div>
<div class="form-group">
<div>
<label>Choose Album:</label>
#if (ViewBag.Folders != null)
{
#Html.DropDownList("folders", new SelectList(ViewBag.Folders as IEnumerable<SelectListItem>, "Value", "Text"), "--- Select Album ---", new { #class = "form-control" })
}
</div>
</div>
<div class="form-group">
<div>
<input type="submit" value="Upload" class="btn btn-default" />
</div>
</div>
</div>
</div>
}
Thanks.
in order to get the folder, give your dropdownlist the corresponding name ...
#Html.DropDownList("folders"...
will result in your DDL to have the name "folders" ... which will try to post back a single item... folders in your method is a IEnumerable<SelectListItem> ... the modelbinder is incapable to convert that ...
try
#Html.DropDownList("folder"...
note the missing s
now the name corresponds to the string folder parameter in your method... which the binder will most likely be able to bind for you...
if you debug errors like this, use the debugger to have a look at HttpContext.Request.Params, which will show you what was coming back when the request was made...
Parameter type should be changed from IEnumerable to String as view returns only selected item NOT collection.
//POST: Home
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(IEnumerable<HttpPostedFileBase> file, string folder, string folders)
{
// some code here
}
Just wanted to give another option. If you're able to leverage a client-side solution, then you could muscle this a bit with a hidden input value and JQuery.
Add a hidden input control:
<input name="selectedFolder" type="hidden" value="" />
Add some Jquery:
<script type="text/javascript">
$(function(){
$("#folders").on("change", function {
$("#selectedFolder").val($(this).text());
});
});
</script>
Thank you Sakthivel Ganesan, after changing the IEnumerable<SelectListItem> folders in the Controller to string folders, the only thing left to do is to change my Html.DropDownList Value to Text like this...
from :
#Html.DropDownList("folders", new SelectList(ViewBag.Folders, "Value", "Text"), "--- Select Album ---", new { #class = "form-control" })
To:
#Html.DropDownList("folders", new SelectList(ViewBag.Folders, "Text", "Text"), "--- Select Album ---", new { #class = "form-control" })

TagBuilder not generating unqiue id attribute values across ajax requests

I have an issue where I'm using the same template to render some content on a page and the same template is used to render additional content on the page using an AJAX request.
The following code renders the partial razor view:
#model SearchBoxViewModel
<div class="smart-search">
#using (Html.BeginForm("Index", "Search", FormMethod.Get, new { #class = "form-horizontal", role = "form" }))
{
<div class="form-group">
<div class="hidden-xs col-sm-1 col-md-1 col-lg-1 text-right">
#Html.LabelFor(m => m.SearchPhrase, new { #class = "control-label heading" })
</div>
<div class="col-xs-8 col-md-9 col-lg-10">
#Html.TextBoxFor(m => m.SearchPhrase, new {#class = "form-control", placeholder = "for products, companies, or therapy areas"})
</div>
<div class="col-xs-4 col-sm-3 col-md-2 col-lg-1">
<input type="submit" value="Search" class="btn btn-default"/>
</div>
<div class="what-to-search hidden-11 col-sm-11 col-sm-offset-1">
<div class="checkbox">
<label>
#Html.CheckBoxFor(m => m.WhatToSearch, null, false)
#Html.DisplayNameFor(m => m.WhatToSearch)
</label>
</div>
</div>
</div>
}
</div> <!-- /.smart-search -->
The following code makes the AJAX request:
$.ajax(anchor.attr("data-overlay-url-action"))
.done(function (data) {
$("div.overlay").addClass("old-overlay");
$("div.navbar").after(data);
$("div.overlay:not(.old-overlay)")
.attr("data-overlay-url-action", anchor.attr("data-overlay-url-action"))
.hide()
.fadeIn();
$("div.old-overlay")
.fadeOut()
.removeClass("old-overlay");
anchor.addClass("overlay-exists");
});
So what you get is the same partial razor view output on the page twice, once during the page request and once during the AJAX request.
The problem is that TextBoxFor, CheckBoxFor, etc. all make use of TagBuilder.GenerateId to generate the id attribute value but it doesn't account for generating id's across multiple requests where AJAX might be involved. This results in the same id value being output on the page, causing JavaScript to break.
The following is the HTML that is output twice (once during the request and then added in a separate part of the page during an AJAX request):
<div class="smart-search">
<form role="form" method="get" class="form-horizontal" action="/PharmaDotnet/ux/WebReport/Search"> <div class="form-group">
<div class="hidden-xs col-sm-1 col-md-1 col-lg-1 text-right">
<label for="SearchPhrase" class="control-label heading">Search</label>
</div>
<div class="col-xs-8 col-md-9 col-lg-10">
<input type="text" value="" placeholder="for products, companies, or therapy areas" name="SearchPhrase" id="SearchPhrase" class="form-control">
</div>
<div class="col-xs-4 col-sm-3 col-md-2 col-lg-1">
<input type="submit" class="btn btn-default" value="Search">
</div>
<div class="what-to-search hidden-11 col-sm-11 col-sm-offset-1">
<div class="checkbox">
<label>
<input type="checkbox" value="true" name="WhatToSearch" id="WhatToSearch">
NewsManager Search Only
</label>
</div>
</div>
</div>
</form></div>
So the SearchPhrase and WhatToSearch id's are duplicated.
Is there any way to work around this, or is there a better way to render the form elements to avoid this issue?
You could specify your own ID for the items, and then you wouldn't have this ID collision problem. Have you tried setting the id manually: Html.TextBoxFor( ... , new { id = "AnythingHere" }), where the id could be a freshly generated Guid? (Note that you'd probably need to add a prefix, because Guids can start with a number.
So you can use the following. The Guid doesn't look good, and is unnecessarily long. You might want to go with something shorter, like short guid, DateTime.Ticks, ...
#{
var id = "chk_" + Guid.NewGuid().ToString();
}
#Html.CheckBoxFor(..., new { id = id })
#Html.LabelFor(..., new { #for = id })

return 2 values to controller, text remains NULL

trying to pass 2 values back to the controller id', and 'text'...id passes ok but text always returns nulll any idea why?
<div class="modal-body">
<input type="hidden" id="AlertFreeTextId" name="AlertFreeTextId" value="#Model.AlertFreeTextId" />
<input type="hidden" id="Text" name="Text" value="#Model.Text" />
<div class="form-group">
#Html.LabelFor(x => x.Text)
#Html.TextAreaFor(x => x.Text, new { #class = "form-control" })
#Html.ValidationMessageFor(x => x.Text)
</div>
<div>
<a href='#Url.Action("CreateAlertFreeText", "AlertFreeText", new { id = Model.AlertFreeTextId, text = Model.Text})'>
<button class="btn btn-primary">#T("Save")</button>
</a>
</div>
</div>
//controller
public ActionResult CreateAlertFreeText(int id, string text)
{
}
This line here:
<a href='#Url.Action("CreateAlertFreeText", "AlertFreeText", new { id = Model.AlertFreeTextId, text = Model.Text})'>
All this is doing is getting the text that was passed into the View. I assume when you call the view, Model.Text is null, so that's exactly what it's returning.
You need to pull the data from the form when you submit like that.
I'd suggest creating either using a form post, or calling a jquery method to do the post where you can pull the form data.
Maybe something like this: (warning: untested!)
<div class="modal-body">
<input type="hidden" id="AlertFreeTextId" name="AlertFreeTextId" value="#Model.AlertFreeTextId" />
<input type="hidden" id="Text" name="Text" value="#Model.Text" />
<div class="form-group">
#Html.LabelFor(x => x.Text)
#Html.TextAreaFor(x => x.Text, new { #class = "form-control" })
#Html.ValidationMessageFor(x => x.Text)
</div>
<div>
<a href='#' id='alertFreeTextLink'>
<button class="btn btn-primary">#T("Save")</button>
</a>
</div>
</div>
<script>
$(document).ready(function() {
$("#alertFreeTextLink").click(function() {
var url = '#Url.Action("CreateAlertFreeText", "AlertFreeText",
new { id = Model.AlertFreeTextId })';
url = url + "&text=" + $("#Text").val();
$.ajax({
url: url
})
.done(function(response) {
/// Do something here
});
});
});
</script>

Categories