I wanna send checkboxes value from View to Action with viewmodel.
Can you help me ؟
I'm sorry about my terrible English
You could try this way to achieve your requirements
View Model:
public class CheckBoxViewModel
{
public List<Plans> plans { get; set; }
}
public class Plans
{
public int PlanId { get; set; }
public string PlanName { get; set; }
public bool IsSelected { get; set; }
}
Controller When Load View Model:
public IActionResult LoadCheckBoxFromViewModel()
{
var plan = new List<Plans>()
{
new Plans(){ PlanName = "Plan A",PlanId =1, IsSelected= false},
new Plans(){ PlanName = "Plan B",PlanId =2, IsSelected= false},
new Plans(){ PlanName = "Plan C",PlanId =3, IsSelected= false},
new Plans(){ PlanName = "Plan D",PlanId =4, IsSelected= false}
};
var model = new CheckBoxViewModel();
model.plans = plan;
return View(model);
}
Note: I have loaded the checkbox with few predefined value to check. If you need a single checkbox so you can simply customize it as per your requirement. In that case you don't need to loop through the plan checkbox list.
View Of LoadCheckBoxFromViewModel Controller:
#model CheckBoxViewModel
#{
ViewData["Title"] = "LoadCheckBoxFromViewModel";
}
<h4>Load CheckBox From ViewModel</h4>
<h4>Submit value to Controller</h4>
<hr />
#using (Html.BeginForm("GetValueFromCheckBoxUsingViewModel", "StackOverFlow"))
{
for (int i = 0; i < Model.plans.Count; i++)
{
#Html.CheckBoxFor(r => Model.plans[i].IsSelected)
<label> #Model.plans[i].PlanName</label>
#Html.HiddenFor(h => #Model.plans[i].PlanId)
#Html.HiddenFor(h => #Model.plans[i].PlanName)
}
<input id="Button" type="submit" value="Save" class="btn btn-primary" />
}
Controller When Submit Checkbox:
[HttpPost]
public IActionResult GetValueFromCheckBoxUsingViewModel(CheckBoxViewModel checkBoxViewModel)
{
return View(checkBoxViewModel);
}
Output:
Hope it would guide you through.
Related
I have two model classes
public class Item
{
public string Name;
public SubItem SubObject { get; set; }
}
public class SubItem
{
public int Age { get; set; }
public string Work { get; set; }
}
From my code I have something similar to this
public IActionResult ViewAndSend()
{
Item item = new Item
{
Name = "MyName",
SubObject = new SubItem
{
Age = 29,
Work = "Microsoft and google"
},
};
return View(item);
}
and my ViewAndSend.cshtml looks like this
#model TestNavigation.Models.Item
<h2>ViewAndSend example</h2>
<p>#(String.Format("{0} {1}", "Name", Model.Name))</p>
<p>#(String.Format("{0} {1}", "Age", Model.SubObject.Age))</p>
<p>#(String.Format("{0} {1}", "Work", Model.SubObject.Work))</p>
#using (Html.BeginForm("SendSubItem", "Home", FormMethod.Post))
{
#Html.HiddenFor(m => m.SubObject.Age)
#Html.HiddenFor(m => m.SubObject.Work)
<input type="submit" value="Next" />
}
My SendSubItem method looks like this
[HttpPost]
public IActionResult SendSubItem(SubItem subItem)
{
int age = subItem.Age; //age is 0
var work = subItem.Work; // work is null
return View();
}
The ViewAndSend.cshtml prints the correct values. However the SendSubItem method gets an object with 0 as Age and null for Work.
Can anyone explain what I am doing wrong?
You should use Item as the receiving type.
[HttpPost]
public IActionResult SendSubItem(Item item)
{
int age = item.SubObject.Age;
var work = item.SubObject.Work;
return View();
}
I have the following classes:
public class Nationality
{
public int ID { get; set; }
public string name { get; set; }
}
public class PersonalData
{
public List<Nationality> availableNationalities { get; set; }
public PersonalData()
{
availableNationalities = new List<Nationality>();
}
}
In my view, I want to create a DropDownlistFor using the availableNationalities field on the PersonalData.
Follows a piece of view code and an example what I'm trying to do:
#model PersonalData
#Html.DropDownListFor(
model => model.personalData.nationality,
new SelectList(Model.availableNationalities, "ID", "name"),
"Choose please an option",
new { required = "required" }
)
Thank you in advance
Your code will throw an exception as there is no personalData property on your PersonalData view model.
Add one more property in your view model to store the selected option value
public class PersonalData
{
public int SelectedNationality { set;get;}
public List<Nationality> AvailableNationalities { get; set; }
public PersonalData()
{
AvailableNationalities = new List<Nationality>();
}
}
Now in your view you can use the select tag helper (in your ASP.NET Core app)
#model PersonalData
<form asp-controller="Home" asp-action="Create">
<select asp-for="SelectedNationality"
asp-items="#(new SelectList(Model.AvailableNationalities ,"Id","Name"))">
<option>Please select one</option>
</select>
<input type="submit"/>
</form>
If it is a Non core app, you can use the DropDownListFor helper
#Html.DropDownListFor(
a=> a.SelectedNationality,
new SelectList(Model.AvailableNationalities, "ID", "name"),
"Choose please an option",
new { required = "required" }
)
Assuming your GET action method set the AvailableNationalities property on your PersonalData viewmodel object before sending it to the view.
public IActionResult Create()
{
var vm=new PersonalData
{
AvailableNationalities = new List<Nationality>
{
new Nationality { Id=1, Name="USA"},
new Nationality { Id=2, Name="Canada"},
}
};
return View(vm);
}
If all you care about is rendering a SELECT element in the view, you may simply use a List<SelectListItem> instead of List<Nationality> as explained in this post
My code is similar to:
class StudentsViewModel:
public class StudentsViewModel
{
public List<Student> Students { get; set; }
public Student SelectedStudent { get; set; }
public string DisplayMode { get; set; }
}
StudentsController:
[HttpPost]
public ActionResult New(int? page, int? SelectedGroup)
{
// some code
StudentsViewModel model = new StudentsViewModel();
model.Students = db.Students.ToList().ToPagedList(pageNumber, pageSize);
model.SelectedStudent = null;
model.DisplayMode = "WriteOnly";
ViewBag.IDGroup = new SelectList(db.Groups, "IDGroup", "Name");
return View("Index", model);
}
View: Index
<form method="post">
<input type="submit" value="Add Student" formaction="/Students/new" class="btn btn-default" />
//some code
#{
if (Model.SelectedStudent != null)
{
if (Model.DisplayMode == "ReadWrite")
{
Html.RenderPartial("_EditStudent", Model.SelectedStudent);
}
}
if (Model.DisplayMode == "WriteOnly")
{
Html.RenderPartial("_InsertStudent", new StudentList.Models.Student());
}
}</form>
Partial View:
_InsertStudent.cshtml
<div class="form-group">
#Html.DropDownList("IDGroup", String.Empty)
#Html.ValidationMessageFor(model => model.IDGroup)
</div>
I have very big problem because my DropDownList doesn't work... Now I display _InsertStudent when I click on button but it doesn't work... If i have
Html.RenderPartial("_InsertStudent", new StudentList.Models.Student());
directly (without button) it works...
How is it possible that in a razor EditorTemplate the following commands generate a different value for the same ViewModel:
#Html.TextAreaFor(model => model.Value)
#Model.Value
And no, in the Value get property, the value is not changed
Update 1:
Sorry guys for the short message, you know, tired, frustrated...
Made a sample, got rid of all the partials and templates.
Give the textbox number 1, hit add, number 2, hit add, number 3, hit add.
The remove number 2.
The result is an out of sync between the textbox and the displayed value.
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
TestModel testModel = TestModel.Create();
Session["model"] = testModel;
return View("Index", testModel);
}
[HttpPost]
public ActionResult Submit(TestModel submitModel, string submit)
{
// merge values in current form
var testModel = Session["model"] as TestModel;
if (testModel == null) throw new Exception("No current model found.");
testModel.MergeFieldValues(submitModel);
if (submit.StartsWith("Add_"))
{
var rowGroupId = Guid.Parse(submit.Substring("Add_".Length));
TestRowGroup rowGroup = testModel.Groups.SelectMany(g => g.RowGroups).Single(rg => rg.RowGroupId == rowGroupId);
rowGroup.AddFieldRow();
}
if (submit.StartsWith("Del_"))
{
var fieldRowId = Guid.Parse(submit.Substring("Del_".Length));
testModel.RemoveFieldRow(fieldRowId);
}
return View("Index", testModel);
}
}
Model:
public class TestModel
{
public List<TestGroup> Groups { get; set; }
public static TestModel Create()
{
var testModel = new TestModel { Groups = new List<TestGroup>() };
var grp = new TestGroup { RowGroups = new List<TestRowGroup>() };
var rowGrp = new TestRowGroup { RowGroupId = Guid.NewGuid(), FieldRows = new List<TestFieldRow>() };
var fldRow = new TestFieldRow { FieldRowId = Guid.NewGuid(), Fields = new List<TestFormField>() };
var fld = new TestFormField { FieldId = Guid.NewGuid() };
fldRow.Fields.Add(fld);
rowGrp.FieldRows.Add(fldRow);
grp.RowGroups.Add(rowGrp);
testModel.Groups.Add(grp);
return testModel;
}
public void MergeFieldValues(TestModel src)
{
foreach (var srcField in src.Groups.SelectMany(g => g.RowGroups.SelectMany(rg => rg.FieldRows.SelectMany(fr => fr.Fields))))
{
var destField = Groups.SelectMany(g => g.RowGroups.SelectMany(rg => rg.FieldRows.SelectMany(fr => fr.Fields))).FirstOrDefault(f => f.FieldId == srcField.FieldId);
if (destField == null) throw new Exception("Field not found during merge");
destField.Value = srcField.Value;
}
}
public void RemoveFieldRow(Guid fieldRowId)
{
foreach (var group in Groups)
{
foreach (var rowGroup in group.RowGroups)
{
rowGroup.FieldRows.RemoveAll(fieldRow => fieldRow.FieldRowId == fieldRowId);
}
}
}
}
public class TestGroup
{
public List<TestRowGroup> RowGroups { get; set; }
}
public class TestRowGroup
{
public List<TestFieldRow> FieldRows { get; set; }
public Guid RowGroupId { get; set; }
public void AddFieldRow()
{
var newRow = new TestFieldRow
{
Fields = new List<TestFormField>()
};
newRow.FieldRowId = Guid.NewGuid();
var fld = new TestFormField { FieldId = Guid.NewGuid() };
newRow.Fields.Add(fld);
FieldRows.Add(newRow);
}
}
public class TestFieldRow
{
public Guid FieldRowId { get; set; }
public List<TestFormField> Fields { get; set; }
}
public class TestFormField
{
public Guid FieldId { get; set; }
public string Value { get; set; }
}
View:
#model FieldTest.Models.TestModel
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
#using (Html.BeginForm("Submit", "Home", FormMethod.Post))
{
for (int g = 0; g < Model.Groups.Count; g++)
{
for (int rg = 0; rg < Model.Groups[g].RowGroups.Count; rg++)
{
for (int fr = 0; fr < Model.Groups[g].RowGroups[rg].FieldRows.Count; fr++)
{
for (int f = 0; f < Model.Groups[g].RowGroups[rg].FieldRows[fr].Fields.Count; f++)
{
#Html.HiddenFor(model => model.Groups[g].RowGroups[rg].FieldRows[fr].Fields[f].FieldId)
#Model.Groups[g].RowGroups[rg].FieldRows[fr].Fields[f].Value
#Html.TextBoxFor(model => model.Groups[g].RowGroups[rg].FieldRows[fr].Fields[f].Value)
<button onclick="return confirm('Are you sure you would like to remove this row?');" type="submit" value="#string.Format("Del_{0}", Model.Groups[g].RowGroups[rg].FieldRows[fr].FieldRowId)" name="submit">Remove</button>
<hr />
}
}
<button type="submit" value="#string.Format("Add_{0}", Model.Groups[g].RowGroups[rg].RowGroupId)" name="submit">Add</button>
}
}
<input type="submit" value="Submit" name="submit" />
}
</body>
</html>
More importantly, are you sure this is an EditorTemplate problem? If you put the code in your main view, does it also happen? Did you try that? Or did you assume it was an EditorTemplate problem?
Since you neglected to provide any context for your question, all we can do is guess. More than likely, you have modified the contents of the view model in a post operation, and are now surprised that the Html helpers are using the old value rather than the value from the model.
If so, this is "by design", and a well documented (hundreds if not thousands of questions already here on SO about this issue). The MVC Helpers prefer the contents of the ModelState over the model itself in post operations. You have to clear the ModelState in order to work around it.
What I want to do is create a CheckBoxList property so the editor could choose facilities specific for current page (hotel name) in BO, and render content based on what is checked.
I've created a model:
public class Facility
{
public int Id { get; set; }
public string Description { get; set; }
public string IconUrl { get; set; }
public List<Facility> GetFacilities()
{
return new List<Facility>()
{
new Facility() { Id = 4, Description = "Free parking", IconUrl = "" },
new Facility() { Id = 6, Description = "Spa", IconUrl = "" },
new Facility() { Id = 7, Description = "Free Wifi", IconUrl = "" },
new Facility() { Id = 2, Description = "Tennis", IconUrl = "" },
new Facility() { Id = 9, Description = "Room service", IconUrl = "" },
new Facility() { Id = 10, Description = "Fitness", IconUrl = "" }
};
}
}
How can I create a CheckBoxList with the values set in GetFacilities() method? Or should I create a new class in AppCode folder with this method? Where is the best place to put this kind of functionality, and how can I achieve this?
Your Facility model should contain a boolean value to indicate if its been selected
public class FacilityVM
{
public int Id { get; set; }
public string Description { get; set; }
public bool IsSelected { get; set; }
{
public class HotelVM
{
public int ID{ get; set; }
....
public List<FacilityVM> Facilities { get; set; }
}
Controller
public ActionResult Edit(int ID)
{
HotelVM model = new HotelVM();
model.Facilities = // populate the list of available facilities
// Get the hotel from repository and map properties to the view model
return View(model);
}
public ActionResult Edit(HotelVM model)
{
...
foreach(FacilityVM facility in model.Facilities)
{
if (facility.IsSelected)
{
// do something
}
}
....
}
View
#model HotelVM
#using (Html.BeginForm())
{
// render properties of hotel
....
for (int i = 0; i < Model.Facilities.Count; i++)
{
#Html.HiddenFor(m => m.Facilities[i].ID);
#Html.HiddenFor(m => m.Facilities[i].Description);
#Html.CheckBoxFor(m => m.Facilities[i].IsSelected)
#Html.LabelFor(m => m.Facilities[i].IsSelected, Model.Facilities[i].Description)
}
<input type="submit" value="Save" />
}
I think you're thinking about this the wrong way as suggested by Stephen (unless I am misunderstanding your question). You are creating a list of key/value pairs and only one will be selected in the BO and so only one will published to the front-end (regardless of the use of it).
So, in the BO you only need a dropdown list with the key/values pairs. You can create this with the "Dropdown list (publishing keys)" datatype. Also consider using the "SQL dropdown" list datatype as this would give you far more flexibility.
If you then need to convert the selected ID into a Facility object, do this separately using a class implementing the IPropertyEditorValueConverter interface. See here for more information:
http://our.umbraco.org/documentation/extending-umbraco/Property-Editors/PropertyEditorValueConverters