ASP.NET MVC not passing select list - html

I have the following form:
#using (Html.BeginForm())
{
#Html.LabelFor(a => a.SomeText)
#Html.TextBoxFor(a => a.SomeText, new { #class = "form-control" })
#Html.ValidationMessageFor(a => a.SomeText)
<select name="ListOne" id="ListOne">
#foreach (var item in Model.ListOne)
{
<option value="#item.Id">#item.Name</option>
}
</select>
#Html.DropDownListFor(a => a.ListTwo, listTwo, null);
<input type="submit" value="Do Stuff" class="btn-primary"
asp-controller="My" asp-action="DoStuff"/>
. . .
}
On the server side, I have a simple controller method:
public async Task<IActionResult> DoStuff(MyViewModel myViewModel)
{
// ...
}
A breakpoint here shows that neither select list gets passed through, despite them both being visible in the HTML.
The VM looks like this:
public class MyViewModel
{
public string? SomeText { get; set; }
public SelectList? ListOne { get; set; } = new(new List<SelectListItem>());
public SelectList? ListTwo { get; set; } = new(new List<SelectListItem>());
}
ListOne and ListTwo are both null.
Please - could someone tell me why?

Related

DropDownListFor not selecting

I have a DropDownListFor that doesn't seem to be setting the expected Model property. Here's the HTML:
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedItem,
new SelectList(Model.ItemList, "Id", "Desc"), null,
new { #class = "selected-list", #size = "3" });
<div>
#Model.SelectedItem
</div>
<input type="submit" value="Do Stuff"
asp-controller="My"
asp-action="DoStuff"
asp-route-itemId="#Model.SelectedItem" />
</div>
}
The div is just there for debugging purposes, and it either shows 0 or blank.
The underlying model has a property:
public int SelectedItem { get; set; }
I've also tried a string:
public string SelectedItem { get; set; } = String.Empty;
(Hence why 0 or blank)
The actual list itself displays fine, it just doesn't update the model on select. How can I get it to update the model?
If you use asp-route-itemId, your action need contains parameter named itemId to receive the value. But for your scenario, it seems to be useless to receive such value, because it will always receive the value you set instead of the dropdown changed value.
Here is a simple demo you could follow and check if any difference with yours:
Model
public class TestVM
{
public string SelectedItem { get; set; } = String.Empty;
public List<Item> ItemList { get; set; }
}
public class Item
{
public int Id { get; set; }
public string Desc { get; set; }
}
View(Index.cshtml)
#model TestVM
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedItem,
new SelectList(Model.ItemList, "Id", "Desc"), null,
new { #class = "selected-list", #size = "3" });
<div>
#Model.SelectedItem
</div>
<input type="submit" value="Do Stuff"
asp-controller="Home"
asp-action="DoStuff" />
}
Controller
[HttpGet]
public IActionResult Index()
{
//Note: hard-coded the model just for easy testing.....
var model = new TestVM()
{
SelectedItem = "1",
ItemList = new List<Item>()
{
new Item(){Id=1,Desc="aa"},
new Item(){Id=2,Desc="bb"},
new Item(){Id=3,Desc="cc"}
}
};
return View(model);
}
[HttpPost]
public IActionResult DoStuff(TestVM model)
{
return View("index", model);
}
Result

Passing list of models from one page to controller

I've tried to pass a list of models to controller but with no luck. I have a problem with generating empty view and then pass values from filled forms to controller. What I have:
Models
public class PostsModel
{
[Required]
[DataType(DataType.DateTime)]
public DateTime PublishDate { get; set; }
[Required]
public List<PostModel> Posts { get; set; }
}
public class PostModel
{
public string Language {get;set;}
public string X {get;set;}
public string Y {get;set;}
// and other properties
}
Controller
public IActionResult New()
{
ViewData["ButtonName"] = "Add";
return View(new PostsModel { PublishDate = DateTime.UtcNow });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> New(PostsModel model)
{
if (ModelState.IsValid)
{
// some code
// never reaches this point
}
return View(model);
}
Form:
<form method="post">
<h4>XYZ</h4>
<hr />
#{
Model.Posts = new List<PostModel>(2);
for (var i = 0; i < 2; i++)
{
Model.Posts.Add(new PostModel());
}
foreach (var test in Model.Posts)
{
<h4>xyz</h4>
<div class="form-group">
<label asp-for="#test.Subject">Temat</label>
<input asp-for="#test.Subject" class="form-control" />
<span asp-validation-for="#test.Subject" class="text-danger"></span>
</div>
}
}
<button type="submit" class="btn btn-primary">#ViewData["ButtonName"]</button>
</form>
Of course model is never valid. I don't have an idea how to do such functionality.
As #StephenMuecke said, using for-loop is working approach. In this particular problem that I had it's enough to do:
Controller:
public IActionResult New()
{
ViewData["ButtonName"] = "Add";
// example:
return View(new PostsModel { PublishDate = DateTime.UtcNow, Posts = new List<PostModel>(2) { new PostModel(), new PostModel() } });
}
View:
for (var i = 0; i < Model.Posts.Count; i++)
{
<h4>xyz</h4>
<div class="form-group">
<label asp-for="#Model.Posts[i].Subject">Temat</label>
<input asp-for="#Model.Posts[i].Subject" class="form-control" />
<span asp-validation-for="#Model.Posts[i].Subject" class="text-danger"></span>
</div>
#*and so one*#
}
I also want to thank M. Kostrzewski and M. Kaletka who also helped me on some .net group

ASP.NET Core select tag

I am learning asp .net core, and for that purpose I am developing simple blogging application. I want to edit existing post and I want to have dropdown with categories of posts but to have selected by default current category of the post. I am failing to do it on the view.
Here is my ViewModel:
namespace Blog.Models.ViewModels
{
public class CategoryViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public IEnumerable<Posts> Posts { get; set; }
public IEnumerable<Categories> Categories { get; set; }
}
}
Here is my controller action:
[HttpGet]
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var posts = _db.Posts.ToList();
var post = posts.Where(m => m.Id.Equals(id));
var cats = _db.Categories.ToList();
CategoryViewModel categoryViewModel = new CategoryViewModel();
categoryViewModel.Posts = post;
categoryViewModel.Categories = cats;
return View(categoryViewModel);
}
And finally here is my view:
<label for="postCategory">Category</label>
<select>
#foreach (var cats in Model.Categories)
{
<option value="#Html.DisplayFor(m => cats.Id)">
#Html.DisplayFor(m => cats.Title)
</option>
}
</select>
My question is how to make something like this in view:
<option value="#Html.DisplayFor(m => cats.Id)" **if(post.Category = cats.Id){ print selected }**>
#Html.DisplayFor(m => cats.Title)
</option>
Try and change your ForEach Loop like this:
#foreach (var cats in Model.Categories)
{
<!option value="#cats.Id" #((#Model.Posts.FirstOrDefault == cats.Id) ? "selected" : string.Empty)>#cats.Title()</!option>
}
Important ist the ! in the tag.

MVC, Razor - Submitting form (inside #if) gives empty object in post

I am trying to save some changes to a database.
The view gets a Model, and should be able to make changes and have them saved. However, when i submit the form, the ContactInfo parameter in the post method is not null, but all the properties are.
I'm using MVC5 with Razor. the script is in a seperate .ts-file
In controller:
[HttpPost]
public bool SaveInfoChanges(ContactInfo editedContactInfo)
{
// Save data
return true;
}
Script:
export function saveInfoChanges() {
$("#EditContactInfoForm").submit();
};
HTML:
#if (true)
{
#using (Html.BeginForm("SaveInfoChanges", "ContactInfoBox", FormMethod.Post, new { id = "EditContactInfoForm" }))
}
<table>
#Html.HiddenFor(model => model.Name)
#Html.HiddenFor(model => model.Address1)
#Html.HiddenFor(model => model.Address2)
#Html.HiddenFor(model => model.ZipAndCity)
#Html.HiddenFor(model => model.Country)
<tr>
<td>test</td>
<td>
#Html.TextBoxFor(model => model.Address3, new { id = "ContactTypeInput", placeholder = "", style = "width:300px" })
</td>
</tr>
</table>
}
}
Model:
public class ContactInfo
{
public string ContactInfoBoxHeaderText { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public string ZipAndCity { get; set; }
public string Country { get; set; }
}
I can't think of more relevant information to give, but please don't hesitate to ask.
Thanks in advance!
Removing the #if solved the problem. I just need to find another way to hide/show the elements.

Object reference not set to an instance of an object MVC

this is my models:
public class Ressource
{
[Key]
public int RessourceId { get; set; }
public string TitreR { get; set; }
public string Link { get; set; }
public string Type { get; set; }
public string Desc { get; set; }
public int Position { get; set; }
public int Rating { get; set; }
public string Tags { get; set; }
public int SectionId { get; set; }
public int UserId { get; set; }
}
public class Section
{
[Key]
public int SectionId { get; set; }
public string Titre { get; set; }
public String Tags { get; set; }
public virtual ICollection<Ressource> Ressources { get; set; }
}
public class structure
{
public Ressource ress;
public List<string> liste;
}
In this view, I enter the resource's title (TitreR), a description (Desc) and I choose from a list of tags which ones I want to link with this resource as well as entering a tag:
#model Mocodis.Models.structure
#{
ViewBag.Title = "AjouterRessource";
}
<h2>AjouterRessource</h2>
#using (Html.BeginForm("AjouterRessource", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<input type="hidden" name="SectionId" value="#Model.ress.SectionId" />
<legend>Ressource</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ress.TitreR)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ress.TitreR)
#Html.ValidationMessageFor(model => model.ress.TitreR)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ress.Desc)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ress.Desc)
#Html.ValidationMessageFor(model => model.ress.Desc)
</div>
</fieldset>
}
<form id="orderProductForm219" name="orderProductForm219" method="post" >
<b>Choisir les mots clés:</b>
<br /><br />
#foreach (string s in #Model.liste)
{
<input type="checkbox" name="tags[]" value="#s"> #s<br />
}
<input type="text" name="tags" id="tags" value="" />
<p>
<input type="submit" value="Create" />
<input type="hidden" name="tag" value="tags" />
<input type="hidden" name="res" value="#Model.ress" />
</p></form>
(I didnt put the javascript for it)
Finally the controllers are:
public ActionResult AjouterRessource(int SectionId)
{
Ressource res = new Ressource();
res.SectionId = SectionId;
Section sec = _db.Sections.Where(r => r.SectionId == SectionId).FirstOrDefault();
char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
List<string> l = new List<string>();
l = sec.Tags.Split(delimiterChars).ToList();
structure s = new structure();
s.ress = res;
s.liste = l;
return View(s);
}
public string Check ( string list, string s)
{
char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
List<string> l = new List<string>();
List<string> liste = new List<string>();
l = s.Split(delimiterChars).ToList();
liste = list.Split(delimiterChars).ToList();
foreach (string item in l)
{
if (!liste.Contains(item))
liste.Add(item);
}
return (string.Join(" ", liste.ToArray()));
}
[Authorize]
[HttpPost]
[InitializeSimpleMembership]
public ActionResult AjouterRessource(Ressource res, int SectionId, string tag)
{
if (ModelState.IsValid)
{
res.SectionId = SectionId;
var model = _db.Sections.Where(c => c.SectionId == SectionId).FirstOrDefault();
res.Tags = tag;
model.Tags = Check(model.Tags, tag);
_db.Entry(model).State = EntityState.Modified;
_db.Entry(res).State = EntityState.Added;
_db.SaveChanges();
return RedirectToAction("Section", new { SectionId = SectionId });
}
return View();
}
I keep getting: Object reference not set to an instance of an object on the line: #Html.ValidationSummary(true) in my view. Can you tell me how to fix it please?
Thank you
Every time I have gotten that error it has been from not initializing something. Looking through your code the only spot I am seeing that might need it is when you are setting structure. You might try putting a constructor on that class to initialize the fields and see if that helps. something like
public structure()
{
ress = new Resource();
liste = new List<string>();
}
You probably need to add the { get; set; } to the resource and list under structure as well. Hopefully this helps.