Strange Behavior in Razor MVC while using Html.Helpers - c#

I am using Razor HtmlHelpers.
using the code below i tried to print the value of ViewItemDto but it always show 0 for using #Html.TextBoxFor or any #Html...For(x=>..) method.
Does anybody have a idea why this is happening?
Note - The method is returning proper value as i can debug and see the value in debug window on views side.
[DataContract]
[Serializable]
public class ViewItemDto
{
[DataMember]
public decimal ViewItemId { get; set; }
[DataMember]
public string ItemName { get; set; }
}
From Controller Return
public ActionResult Index()
{
ViewItemDto viewItem = new ViewItemDto();
viewItem.ItemName = "OldData";
viewItem.ViewItemId = 10;
return View(viewItem);
}
public PartialViewResult SaveData(ViewItemDto viewItem)
{
viewItem.ItemName = "NewData";
viewItem.ViewItemId = 100;
return PartialView("ViewUserControl1", viewItem);
}
On View ViewUserControl1
#model Testing.Models.ViewItemDto
<div id="divSave">
#using (Ajax.BeginForm("SaveData", "Home", new AjaxOptions()
{
UpdateTargetId = "divSave",
OnSuccess = "OnSuccess",
InsertionMode = InsertionMode.Replace
}))
{
#Html.TextBoxFor(x => x.ViewItemId)//Shows 10
#Html.TextBox("ID", Model.ViewItemId) //Shows proper value 100
#Html.TextBoxFor(x => x.ItemName)//Shows oldData value
<input type="submit" name="name" value="Submit" />
}
and Index.cshtml
#model Testing.Models.ViewItemDto
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
#Html.Partial("ViewUserControl1", Model);

Shouldn't you be:
return PartialView(viewItem);
instead of:
return viewItem;

By changing the code of your controller to the following it worked here:
public PartialViewResult SaveData(ViewItemDto viewItem)
{
viewItem.ViewItemId = 100;
return viewItem;
}
I was unabled to reproduce your problem, since the code provided not even compiled.

Related

Using a form submit button to go to an external link with two inputs in ASP.NET MVC

I'm very new to MVC and I'm not sure quite how the forms work. Here's what i want to do:
So I've got two text boxes and an enter button in a form I want to put two values into the textboxes and use them in my external link. Here's the code I am trying to use, i know it's not correct at all but should show you what I'm trying to do:
View:
#model Test.Models.Home
#{
ViewBag.Title = "Main";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("GetMessage()", "Home", FormMethod.Post))
{
#Html.Label("Location1: ")
#Html.TextBoxFor(model => model.Location1)
#Html.ValidationMessageFor(model => model.Location1)
#Html.Label("Location2: ")
#Html.TextBoxFor(model => model.Location2)
#Html.ValidationMessageFor(model => model.Location2)
<button type="submit">Enter</button>
}
Controller:
using System.Web.Mvc;
using BBWebApp.Models;
namespace Test.Controllers
{
public class HomeController : Controller
{
public ActionResult Main()
{
//var name = new Home() { Name = "Google maps API" };
return View();
}
[HttpPost]
public ActionResult Location(Home model)
{
if (ModelState.IsValid)
{
//TODO: SubscribeUser(model.Email);
}
return View("Main", model);
}
[HttpPost]
public ActionResult GetMessage()
{
return Redirect("https://example.com/" + Location1 + "/" + Location2);
}
}
}
Model:
public class Home
{
public string Location1 { get; set; }
public string Location2 { get; set; }
public string Name { get; set; }
}
As you can see I'm trying to get the form to trigger the redirect function under getMessage() but obviously this code is flawed as I don't fully understand how it works. As i said I'm very new to MVC so any help with this would be much appreciated.
This code is very good for starting. Only have some minor problems:
On your view's using block, remove paranthesis from action method
GetMessages
like that
#using (Html.BeginForm("GetMessage", "Home", FormMethod.Post))
{
#Html.Label("Location1: ")
#Html.TextBoxFor(model => model.Location1)
#Html.ValidationMessageFor(model => model.Location1)
#Html.Label("Location2: ")
#Html.TextBoxFor(model => model.Location2)
#Html.ValidationMessageFor(model => model.Location2)
<button type="submit">Enter</button>
{
Then you need to get your model and use variables on your controller's method
[HttpPost]
public ActionResult GetMessage(Home model)
{
return Redirect("https://example.com/" + model.Location1 + "/" + model.Location2);
}
and you are good to go.

ASP.NET MVC Ajax form not routing values

This is a sister question from another question I posted (here). Many thanks to #nurdyguy and all of the people who helped me previously. However, I am having an issue where I am unable to pass a list of values to a destination controller that's in another View. My desired output is to send over the complete List object but right now I am getting a value count of zero (0) when it gets to the controller.
Here is my Model:
using System.Collections.Generic;
namespace Foo.Models
{
public class FooViewModel
{
public List<Foo> FooCollection = new List<Foo>();
/*Contains two properties
string CarName {get; set;}
string Color {get; set;}
List<Features> Features = new List<Features>();
*/
}
}
My View
#model Foo.Models.FooViewModel
#{
var RedCars = Model.FooCollection.Where(c => c.Color == "Red").ToList();
... //{yellow, blue, green}
}
<div id="FooCollection">
<section class="no-padding-top no-padding-bottom">
<div class="container-fluid">
<div class="public-user-block block">
<div class="row d-flex align-items-center">
<!--Red Cars-->
#using (Ajax.BeginForm("../Bar/Index/Red", null,
new AjaxOptions
{
HttpMethod = "post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "CarsList"
}, new { id = "RedCarsForm" }))
{
<input type="hidden" name="Cars" value="#RedCars" />
<div id="status-container" class="col-lg-3 d-flex align-items-center">
<button type="submit">#RedAlerts.Count</button>
<strong>Red Cars</strong>
</div>
}
<!-- same structure for yellow, green, blue --!>
</section>
</div>
My Controller:
public ActionResult Index()
{
foreach (var car in db.database.Db_GetCars())
{
model.FooCollection.Add(new Foo()
{
CarName = car.CarName,
Color= car.Color
});
}
return View(model);
}
Destination Controller:
namespace Foo.Controllers
{
public class BarController: Controller
{
BarViewModel model = new BarViewModel();
[HttpPost, Route("/Bar/Index/{color}")]
public ActionResult Index(List<Foo> Cars)
{
//logic goes here
return View(model);
}
}
}
I spent some time digging around the best practices to route data but most places I've went have their forms set up like mine and it seems to work (for them). I even passed (as the second parameter) new { Cars = RedCars } but I still get zero (0). Is there something I am missing? Many thanks in advance!

In MVC, posting of form return empty model

I have the following viewModel
public class ExerciceViewModel
{
public string Code { get; set; }
public string Titre { get; set; }
public int QuestionCourante { get; set; }
}
the following view
#model MonEcoleVirtuelle.ViewModel.ExerciceViewModel
#{
ViewBag.Title = "Test";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Test</h2>
#using (Html.BeginForm("test", "exercice", FormMethod.Post))
{
#Model.Code <br />
#Model.Titre<br />
#Model.QuestionCourante<br />
<br />
<br />
Model.Code = "Code Modifie";
<input type="submit" value="Post Moi Ca!" name="fini" />
}
and the following controller methods
[HttpPost]
public ActionResult Test(ViewModel.ExerciceViewModel model)
{
if (ModelState.IsValid)
{
return Content(model.Code);
}
return View(model);
}
[HttpGet]
public ActionResult Test()
{
var vm = new ViewModel.ExerciceViewModel { Code = "code1", Titre = "Mon titre", QuestionCourante = 1 };
return View(vm);
}
When I submit the form, the model passed is empty, all properties are reset, not keeping the original values. What am I missing.
thanks
well, instead of #Model.Code which just display the values, you need some inputs.
So #Html.TextBoxFor(m => m.Code) for example
To manage a collection, you can do something like that :
#for (var i = 0; i < Model.Collection.Count; i++) {
Html.TextBoxFor(m => Model.Collection[i].Property)
}
You have not included any input fields in your view.
The #Model.Code etc only output the value of the field. To be able to post back elements they need to be form elements, like inputs. Use something like
#Html.TextBoxFor(p=>p.Code)
to create input fields that can then be posted back.
For a more complete guide see MSDN at http://msdn.microsoft.com/en-us/library/dd410596(v=vs.100).aspx

How to convert my simple ASP.NET MVC 4 application to AJAX?

How to I convert my simple MVC4 todo list application to AJAX?
The ideal answer would give me the steps that would lead to a successful conversion of this example to AJAX.
Note: I don't need an AJAX tutorial so much as an understanding of how the ASP.NET MVC architecture supports it.
Side Question: Why does #Html.EditorFor(model => model.TodoItemToCreate) bring back the value that was typed in even though the view model sets with this.TodoItemToCreate = null?
Model
public class TodosViewModel
{
List<string> todoItems;
public List<string> TodoItems
{
get { return this.todoItems ?? (todoItems = new List<string>()); }
}
[Display(Name="What do you need to do?")]
public string TodoItemToCreate { get; set; }
public bool AcceptTodoItem()
{
bool isThereAnItemToAccept = !string.IsNullOrWhiteSpace(this.TodoItemToCreate);
if (isThereAnItemToAccept)
{
this.TodoItems.Add(this.TodoItemToCreate);
this.TodoItemToCreate = null;
}
return isThereAnItemToAccept;
}
}
Controller
public class TodosController : Controller
{
public ActionResult Index()
{
return View(new TodosViewModel());
}
public ActionResult Create(TodosViewModel todosViewModel)
{
todosViewModel.AcceptTodoItem();
return View("Index", todosViewModel);
}
}
Index View
#model Programming.LearnWeb.Models.TodosViewModel
#{
ViewBag.Title = "Todos";
}
#using (Html.BeginForm("Create", "Todos"))
{
#Html.Partial("List")
#Html.LabelFor(model => model.TodoItemToCreate)
#Html.EditorFor(model => model.TodoItemToCreate)
<input type="submit" value="Create" />
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
List View
#model Programming.LearnWeb.Models.TodosViewModel
#{ int i = 0; }
<table>
#foreach (var todoItem in Model.TodoItems)
{
<tr>
<td>
#Html.Hidden("TodoItems[" + i++ + "]", todoItem)
#todoItem
</td>
</tr>
}
</table>
I got this done on my own - the result is at https://github.com/gabrielgreen/Todos.Mvc if anyone is interested or has any comments.
I put a fair amount of effort in and would appreciate any feedback that indicates if I did it right.

Asp:net MVC 3: #Html.EditorFor a subcollection of my model in a template?

I've been stuck a long time to edit a subcollection of my model, the collection of the model was coming null.
I finally found a solution, but I find it a little dirty:
First my tests datas:
Model object:
public class ContainerObject
{
public String Title { get; set; }
public List<ContainedObject> ObjectList { get; set; }
}
Sub collection object:
public class ContainedObject
{
public int Id { get; set; }
public String Text { get; set; }
public Boolean IsSelected { get; set; }
}
Controller method which generate the object
public ActionResult TestForm()
{
return View(new ContainerObject()
{
Title = "This is a sample title",
ObjectList = new List<ContainedObject>()
{
new ContainedObject(){Id=1, IsSelected = true, Text="ObjectOne"},
new ContainedObject(){Id=2, IsSelected = false, Text="ObjectTwo"},
new ContainedObject(){Id=3, IsSelected = true, Text="ObjectThree"},
new ContainedObject(){Id=4, IsSelected = false, Text="ObjectFour"},
}
});
}
Controller which receive the edited object
[HttpPost]
public ActionResult TestFormResult(ContainerObject filledObject)
{
return View();
}
The view
#model WebTestApplication.Models.ContainerObject
#{
ViewBag.Title = "TestForm";
}
#using (Html.BeginForm("TestFormResult","Home", FormMethod.Post)){
#Html.EditorFor(x => x.Title)
Html.RenderPartial("ContainedObject", Model.ObjectList);
<input type="submit" value="Submit"/>
}
The partial view(ContainedObject.cshtml)
#model IEnumerable<WebTestApplication.Models.ContainedObject>
#{
ViewBag.Title = "ContainedObject";
int i = 0;
}
#foreach (WebTestApplication.Models.ContainedObject currentObject in Model)
{
<br />
#Html.Label(currentObject.Text);
#Html.CheckBox("ObjectList[" + i + "].IsSelected", currentObject.IsSelected);
#Html.Hidden("ObjectList[" + i + "].Id", currentObject.Id);
#Html.Hidden("ObjectList[" + i + "].Text", currentObject.Text);
i++;
}
This is actually working, but I've one problem:
I've to generate names myself and specify the property of the container object
I tried to use Html.EditorFor instead of Html.RenderPartial in the view, the problem is that it generate me the name "ObjectList.[0].Id"(with a additional . between the property name and the accessor).
I also tried to use only #Html.EditorFor in the partial view, but it create vars with the name of the object.
If I don't use any template, it works:
#model WebTestApplication.Models.ContainerObject
#{
ViewBag.Title = "TestForm";
}
#using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post))
{
#Html.EditorFor(x => x.Title)
for (int i = 0; i < Model.ObjectList.Count; i++)
{
<br />
#Html.Label(Model.ObjectList[i].Text);
#Html.CheckBoxFor(m => Model.ObjectList[i].IsSelected);
#Html.HiddenFor(m => Model.ObjectList[i].Id);
#Html.HiddenFor(m => Model.ObjectList[i].Text);
}
<br /><input type="submit" value="Submit"/>
}
But here it's a simple template, but in my real case, I will have much more data, and this will be re-used multiple time. So what is my best option?
You can simplify your code by introducing the EditorTemplate. Here is how:
The main view remains pretty much the same except we replaced RenderPartial with EditorFor:
TestForm.cshtml
#model WebTestApplication.Models.ContainerObject
#{
ViewBag.Title = "TestForm";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post)) {
#Html.EditorFor(m => m.Title)
#Html.EditorFor(m => m.ObjectList);
<input type="submit" value="Submit" />
}
Then create a folder named EditorTemplates under Views/Home (assuming your controller is Home):
and add the following template for the ContainedObject:
ContainedObject.cshtml
#model WebTestApplication.Models.ContainedObject
<p>
#Html.DisplayFor(m => m.Text)
#Html.CheckBoxFor(m => m.IsSelected)
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.Text)
</p>
The editor will automatically iterate through the list of objects rendering the view for each of them. Hope it helps.
I found this thread while looking for something else related. Denis has the correct answer, but I thought I would add some syntax in case anyone else comes across this:
If you have an editor template named "SomeTemplate.cshtml" you can use it for a list of Item as follows in your view:
#for (var i = 0; i < Model.ObjectList.Count(); i++)
{
#Html.EditorFor(m => m.ObjectList[i], "SomeTemplate")
}
Then in your editor template:
#model WebTestApplication.Models.ContainedObject
<br />
#Html.Label(Model.Text);
#Html.CheckBoxFor(m => m.IsSelected);
#Html.HiddenFor(m => m.Id);
#Html.HiddenFor(m => m.Text);

Categories

Resources