Iam Asp.net Webform Developer and are trying to learn .net MVC 5.
I know how to make partial view with only static html tags in MVC 5.
But can i in a MVC partial View also have a form with textboxes and a submit buttion ?
If yes, so where do i write Postback function for this partial View for get its posted values ,in which controller ?
Yes, You can have text boxes and a submit button in partial view as well.
Lets say for example you have a product application, and your main page (View) is displaying all the product available.
so in order to show the product you need to pass a model
#model IList<xyzRetailer.ViewModels.ProductViewModel>
#{
ViewData["Title"] = "Home Page";
}
and you can read the value like:
<div class="col-md-3">
<h2>Product Categories</h2>
<ul>
#foreach (var item in Model.Select(a=>a.Category).Distinct())
{
<li>#item</li>
}
</ul>
</div>
Now to your question if you want to have a a partial view with different view model you can go with tuple or you can have a new object created just for partial view while calling it like below
#Html.Partial("_AddProduct", new yzRetailer.ViewModels.ProductViewModel())
and your partial view will be something like below:
#model xyzRetailer.ViewModels.ProductViewModel
#using (Html.BeginForm("Create", "Home", FormMethod.Post))
{
<div class="input-group">
#Html.TextBoxFor(model => model.Id, new { #class = "hidden" })
#Html.TextBoxFor(model => model.Category, new { #class = "form-control" })
</div><input type="submit" value="Save" class="btn btn-primary btn-block" />
}
And the controller code should go Home-> Create that you have mentioned in #Html.BeginForm.
public async Task<IActionResult> Create(ProductViewModel product)
{
if (!ModelState.IsValid)
{
return this.BadRequest(ModelState);
}
if (string.IsNullOrEmpty(product.Id))
{
var result = await _catelogueManager.AddAsync(product);
}
else
{
var result = await _catelogueManager.UpdateAsync(product.Id, product);
}
var products = await _catelogueManager.GetAllAsync();
return View("Index", products);
}
Related
I am trying to filter a list view using a dropdown as a filter.
My controller:
public async Task<ActionResult> Index(int? TradeExerciseNumber)
{
var TradeExerciseEntries = new TradeExerciseController().GetAll();
ViewBag.TradeExerciseEntries = new SelectList(TradeExerciseEntries, "TradeExerciseID", "TradeExerciseNumber");
if (TradeExerciseNumber != null)
{
return View(await db.TradesModels.Where(x => x.TradeExerciseId == TradeExerciseNumber).ToListAsync());
}
return View(await db.TradesModels.ToListAsync());
}
And my view:
#using (Html.BeginForm())
{
<p>
Find by Exercise Number: #Html.DropDownList("TradeExerciseEntries", -how do I pass value to TradeExerciseNumber in my controller to let it render pls- )
<input type="submit" value="Search" />
</p>
}
Now, how do I pass the dropdownlist value to TradeExerciseNumber in my controller to let it render please? Thank you very much.
Best regards
So this is what I did in my view and it worked:
#using (Html.BeginForm("Index", "Trades")){
<p>
Find by Exercise Number: #Html.DropDownList("TradeExerciseNumber", ViewBag.TradeExerciseEntries as SelectList, null, new { onchange = "submit();" })
</p>
}
I hope it helps. Thanks
I am trying to create sub category for categories. User first select the categories from dropdownlist and then type the subcategory name and clicks submit. Even though dropdownlist elements are properly fill the dropdown list. When I click submit button It creates error. How can I solve this?
My View:
#model CETAPPSUGG.Models.CategorySubCategoryModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.selectedId, new { id = "3" });
// #Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SubCatagories</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.SubCategory.SubCategoryName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SubCategory.SubCategoryName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SubCategory.SubCategoryName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
Upper cat: <div class="col-md-10">
#Html.DropDownListFor(Model => Model.Categories, Model.categoryList)
</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>
My Controller:
public ActionResult Create()
{
var categories = db.Categories.ToList();
CategorySubCategoryModel deneme = new CategorySubCategoryModel();
var list = new List<SelectListItem>();
deneme.Categories = categories;
foreach (Categories c in categories)
{
list.Add(new SelectListItem() { Text = c.CategoryName, Value = c.Id.ToString() });
}
deneme.categoryList = list;
return View(deneme);
}
// POST: SubCatagories/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
// [ValidateAntiForgeryToken]
public ActionResult Create( CategorySubCategoryModel model)
{
string strDDLValue = model.selectedId;
SubCatagories newSubCategory = new SubCatagories();
Categories cat = new Categories();
cat = db.Categories.Find(Convert.ToInt32(strDDLValue));
// cat = db.Categories.Find(Convert.ToInt32(strDDLValue));
newSubCategory.SubCategoryName = model.SubCategory.SubCategoryName;
newSubCategory.UpperCategory = Convert.ToInt32(strDDLValue);
newSubCategory.Categories = cat;
db.SubCatagories.Add(newSubCategory);
db.SaveChanges();
return View();
}
My Model
namespace CETAPPSUGG.Models
{
public class CategorySubCategoryModel
{
SubCatagories SubCatagories { get; set; }
public IEnumerable<Categories> Categories { get; set; }
public IEnumerable<SubCatagories> SubCategories { get; set; }
public IEnumerable<SelectListItem> categoryList { get; set; }
public SubCatagories SubCategory { get; set; }
public string selectedId;
}
}
It creates error in view
You have a bunch of problems here.
Your primary problem is that you are not passing a model back to the View on post, thus the model is null. So, when you attempt to dereference items from the model in the View, a null reference is generated.
First, you are using selectedId but do not set this anywhere. It doesn't get set by magic. What you probably want is #Html.DropDownListFor(model => model.selectedId, Model.categoryList) (note the lowercase m in model in the first parameter, and uppercase M in the second)
Second, don't use a Model in your lambda in the DropDownListFor, use the lowercase model, because uppercase Model is reserved for the actual Model instance. If you want to reference the Model instance, then do something like DropDownListFor(_ => Model.Foo, Model.Foos). Note that I replaced the Model before the lambda with an underscore or some other value that is not Model. Frankly i'm surprised this even works, but there's probably a scoping rule here that overrides the outer Model. Avoid this because it can cause you confusion down the road.
Third, you are passing an IEnumerable to the DropDownListFor as the selected item variable, this won't work on a number of levels. This needs to be a single string value in most cases (sometimes a numerical one, but always a single more basic type that can have ToString() called on it and get a sensible string since DropDownListFor can't display complex objects).
Fourth, You also need to re-populate your DropDownListFor in the Post action, because the contents of a dropdownlist are not posted back, and thus will be null in the model. This, along with the SubCategory derefences in your view are ultimately what is generating the Null Reference exception.
You also need to pass the model back to your view in the Post, but as stated above, it needs to be re-initialized with the Categories as well as SubCategories.
There are probably more problems here, but fix these and you should be on your way.
I'm currently working on a website in MVC, I have created a partial view with a DropDownListFor everytime a value is selected in the DropDownListFor it goes to the HttpPost and adds the value to a List. I also have a ListBoxFor that is bound to this list.
What I would like to achieve:
Everytime a new value is added to the List with the DropDownListFor it should update the ListBoxFor automatically so the selected value gets added to this Listbox. I wonder what the best way would be to achieve this.
Code:
Submit.cshtml:
<div class="create-ingredient">
#Html.Partial("_CreateIngredient")
</div>
<br/>
<div class="add-ingredient">
#Html.Partial("_AddIngredient")
</div>
<br/>
<div class="ingredient-listbox">
#Html.LabelFor(model => model.Ingredients,"Current Ingredients")
#Html.ListBoxFor(model => model.Ingredients, new MultiSelectList(Model.SelectedIngredients), new { style = "width:50%;" })
</div>
_AddIngredient.cshtml (Partial View):
#model Recepten.Models.IngredientSelectModel
#using (Ajax.BeginForm("AddIngredient", "Recipe", new AjaxOptions() { UpdateTargetId = "add-ingredient", HttpMethod = "Post" }))
{
#Html.LabelFor(model => model.Ingredients, "Add Ingredient")
#Html.DropDownListFor(model => model.SelectedIngredient, Model.Ingredients, "Select Ingredient", new { #onchange = "$(this).parents('form').submit();" })
}
AddIngredient:
[HttpPost]
public ActionResult AddIngredient(IngredientSelectModel ing)
{
ing.SelectedIngredients.Add(ing.SelectedIngredient);
return PartialView(ing);
}
IngredientSelectModel:
public RecipeModel Recipe { get; set; }
public IEnumerable<SelectListItem> Ingredients { get; set; }
public int SelectedIngredient { get; set; }
public string addIngredient { get; set; }
public List<int> SelectedIngredients { get; set; }
public IngredientSelectModel()
{
SelectedIngredients = new List<int>();
}
Thank you for your time!
As I think you've figured, the reason the current approach isn't working is that the IngredientSelectModel created for and updated by the AddIngredient action is separate from the one used to populate the ListBox.
If Ajax and unobtrusive JQuery are set up correctly (the browser URL shouldn't change when you select an ingredient), #pinhead's answer will send the selected value to the action, but SelectedIngredients won't accumulate the values you select because its value isn't included in the ajax data. For that to work you need to change the multi-select to be bound to SelectedIngredients:
#Html.ListBoxFor(
model => model.SelectedIngredients,
new MultiSelectList(Model.SelectedIngredients),
new { style = "width:50%;" })
...and move it inside the form declaration so its value is posted to the action along with the new ingredient to add.
That said, I wouldn't say you're doing enough work to justify a round-trip to the server, so after making the above change you could just add the ingredient entirely on the client side like this:
#Html.DropDownListFor(
model => model.SelectedIngredient,
Model.Ingredients,
"Select Ingredient",
new { #onchange = "$('#SelectedIngredients').append('<option>' + $(this).val() + '</option>')" })
I believe one solution is to move your ListBoxFor helper into your partial view so that it is updated and recreated once your action returns the partial view.
Submit.cshtml:
<div class="create-ingredient">
#Html.Partial("_CreateIngredient")
</div>
<br/>
<div class="add-ingredient">
#Html.Partial("_AddIngredient")
</div>
_AddIngredient.cshtml (Partial View):
#model Recepten.Models.IngredientSelectModel
#using (Ajax.BeginForm("AddIngredient", "Recipe", new AjaxOptions() { UpdateTargetId = "add-ingredient", HttpMethod = "Post" }))
{
#Html.LabelFor(model => model.Ingredients, "Add Ingredient")
#Html.DropDownListFor(model => model.SelectedIngredient, Model.Ingredients, "Select Ingredient", new { #onchange = "$(this).parents('form').submit();" })
}
#Html.LabelFor(model => model.Ingredients,"Current Ingredients")
#Html.ListBoxFor(model => model.Ingredients, new MultiSelectList(Model.SelectedIngredients), new { style = "width:50%;" })
I'm having some problems with my code and was hoping someone could give me a hand. Here's the snippet I'm working with:
[Authorize]
public ActionResult EventResults(int id)
{
List<Event> CompetitionEvents = Event.getEventsByCompetitionId(id);
ViewBag.CompetitionEvents = CompetitionEvents;
List<Person> Competitors = Competition.getCompetitorsByCompetitionID(id);
ViewBag.Competitors = Competitors;
List<Results> Results = Competition.getCompetitorResultsPairings(CompetitionEvents, Competitors);
ViewBag.Results = Results;
ViewBag.OrganizerEmail = Competition.getCompetitionById(id).OrganizerEmail;
return View();
}
#model BINC.Models.Results
#using BINC.Models;
#{
var eventList = ViewBag.CompetitionEvents as List<Event>;
var competitorList = ViewBag.Competitors as List<Person>;
var resultList = ViewBag.Results as List<Results>;
}
<h2></h2>
<p>Results:</p>
#using (Html.BeginForm())
{
foreach (var evt in eventList)
{
<fieldset>
<legend>#evt.activity.Name</legend>
<p>Event Description: #evt.activity.Description</p>
#foreach (var competitor in competitorList)
{
foreach (var result in resultList)
{
if (result.EventID == evt.id && result.CompetitorEmail == competitor.Email)
{
<p>Competitor: #competitor.FirstName #competitor.LastName</p>
<p>Score: #result.Score</p>
if (ViewBag.OrganizerEmail.Equals(#User.Identity.Name))
{
#Html.LabelFor(model => model.Score, "New Score ");
#Html.TextBoxFor(model => model.Score, new { maxlength = 10, style = "width:125px" })
<input type="submit" name="submitButton" value="Update" />
}
}
}
}
</fieldset>
}
}
[HttpPost]
public ActionResult EventResults(Results res)
{
//stuff
}
My problem is nothing other than the score is set on my Results object.
For example, when I put the value '15' into the text box and click 'Update', I'm passing the Result model object to the httppost method, which has everything set to null other than the 'score' field that I just entered.
Am I over complicating this? Is there an easier way?
I tried adding
#Html.HiddenFor(model => model.EventID);
#Html.HiddenFor(model => model.CompetitorEmail);
but that didn't seem to help any.
You are having multiple Submit buttons and that could be the issue, also this is not considered as good practise
<input type="submit" name="submitButton" value="Update" />
keep just one submit button at the end of the form
Basically-- make sure you pass the model to view-- and use the Html Helpers (ie TextBoxFor() and HiddenFor)
I don't think it's an issue with the submit button-- but the one thing that would probably help is to actually pass the model to the view. You are using the ViewBag to pass your data. Pass the model to View and your Html Helpers should generate the correct form names in order for the model binding to work.
I have created a form with a dropdown list for 'Region'. Once the form has been submitted I want to be able to view the details from the form. In particular I want the name of the 'Region' to be displayed but I am currently getting the name, ID and labels.
The dropdown list Controller:
public ActionResult Add()
{
var db = new AssociateDBEntities();
var region = db.Regions.Select(r => new { r.RegionId, r.RegionName });
ViewBag.Regions = new SelectList(region.OrderBy(r => r.RegionName).AsEnumerable(), "RegionId", "RegionName");
return View();
}
'Details' Controller:
public ActionResult Details(int id)
{
using (var db = new AssociateDBEntities())
{
ViewData["Region"] = new SelectList(db.Regions.ToList(),"RegionName");
return View(db.Associates.Find(id));
}
}
'Details' View:
<div class="form-grid-1">
<div class="display-label">#Html.LabelFor(model => model.Region)</div>
<div class="display-field">#Html.DisplayFor(model => model.Region)</div>
</div>
How can I just get the name (RegionName) to display?
Just use
#Html.LabelFor(model => model.Region.RegionName)
Or create a DisplayTemplate for Region. Check out
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx