Data Binding in ASP.NET MVC - c#

I know it would be a basic question but I'm a newbie to ASP.Net MVC. I have fetched data from database using LINQ but there is an issue. I wanna bind that data with input fields of a customized webform. (I'm using MVC). I wanna populate the input fields of webform with fetched data. I'm using EF Database first approach.
My Controller and view is attached.
Controller ActionMethod
public class HomeController : Controller
{
public ActionResult Index()
{
AutoRTGSEntities_1 dc = new AutoRTGSEntities_1();
//dc.policies.Where(cb => cb.Section_Key.Contains("SenderBIC"));
return View(dc.policies.Where(cb => cb.Policy_Section.Contains("RTGS")).ToList()); //get RTGS policy section data
}
}
View
#model IEnumerable<Swift_MT_103.policy>
#{
ViewBag.Title = "Home Page";
}
<div> #Model{ #Html.TextBoxFor(x => x.data_Value)) } </div>
<div> <input type="text" name="ReceiverBIC" id="ReceiverBIC" /> </div>
Rest is HTML and CSS. Snap is attached.

Here's a very basic example of how to this. Let's say you have following class:
public class User
{
public int Id { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "E-mailaddress")]
public string E-mail { get; set; }
}
In the controller you get the user:
public ActionResult Index(int id)
{
var user = Db.Users.FirstOrDefault(x => x.Id == id);
if(user != null)
{
return View(user);
}
//Return to the 'Error' view as no user was found
return View("Error");
}
You also need a View to show everything on screen. Make it a strongly typed view, this way you can pass a Model to it. This class will hold all data you want to pass to the view. Code of the view:
//This line lets the view know which class represents the model
#model User
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
Using the Razor syntax instead of plain HTML it is very easy to construct and bind your form elements to the corresponding data. In this case the label will show the value of the Display attribute in the User class and the values of the user will be filled in the textboxes.
More reading:
Getting started with ASP.NET MVC 5
ASP.NET MVC Overview
Update:
In case you have a list of objects, you need to enumerate them in the view:
#model IEnumerable<string>
#foreach (var value in Model)
{
<div>#value</div>
}
And if the model is a class and has a property that is a list:
//Let's say a user has lots of names
public class User
{
public int Id { get; set; }
public List<string> Names { get; set; }
}
//View:
#model User
#Html.TextBoxFor(m => m.Id)
#foreach (var name in Model.Names)
{
<div>#name</div>
}

Try to implement a correct ASP.NET MVC architecture. To get this completed, you'll need to use proper Razor (.cshtml type) Syntax in your Views. Best practice:
Create a dedicated ViewModel class in the Model directory. You might call it CustomerCreditTransferViewModel for example. It should contain all Properties you want to display/edit anywhere on the page.
Once you selected your data from your DBContext in your Action, create an instance of CustomerCreditTransferViewModel and populate all fields from the result.
Update your View to use #model CustomerCreditTransferViewModel instead of Swift_MT_103.policy (believe me, this is going to make your live much easier in future)
Copy-paste your raw HTML Code into the page and start looking for all Fields you want to bind, e.g. Text fields (<input type="text" name="accountno" value="" />) and replace them with the Razor Syntax for Data Binding (#Html.TextBoxFor(x => x.AccountNo)). If done correctly, they should be populated now.
Next step is probably the POST. Follow the base MVC Post technique from the Tutorials. Ensure that the Posted Value is of type CustomerCreditTransferViewModel) again, so you can easily validate values and map back to type of Swift_MT_103.policy.

Related

Add model into model using Html helper HiddenFor C# MVC

I have a model like
public class Model
{
public int Value { get; set; }
public List<OtherModel> List { get; set; }
}
public class OtherModel
{
public int Value1 { get; set; }
public int Value2 { get; set; }
public bool IsPropTrue { get; set; }
}
I am using Model in a View where I'm looping through the List to show data in a table.
Depending on whether one of the properties (IsPropTrue) in OtherModel is true or false, I want to use the HiddenFor Html helper and send the data to the HttpPost controller.
#model Model
#foreach (var item in Model.List)
{
if (item.IsPropTrue)
{
#Html.HiddenFor(model=> item.Value1)
#Html.HiddenFor(model=> item.Value2)
}
}
I think it doesn't work because I should in some way add these properties to the OtherModel, which is inside the Model; But the way I have it now, I am adding properties to Model.
you can do it like this :
#model Model
#foreach (var item in Model.List)
{
if (item.IsPropTrue)
{
#Html.HiddenFor(model => model.List[Model.List.IndexOf(item)].Value1)
#Html.HiddenFor(model => model.List[Model.List.IndexOf(item)].Value2)
}
}
this way the binding system will bind the hidden fields with your List OtherModel in the Model
if you want send an array to server based on the Model you have to use indexer in #Html.HiddenFor .
#model WebApplication1.Models.MyModel
<form>
#if (Model != null && Model.List != null)
{
for (int i = 0; i < Model.List.Count; i++)
{
if (Model.List[i].IsPropTrue)
{
#Html.HiddenFor(model => Model.List[i].Value1)
#Html.HiddenFor(model => Model.List[i].Value2)
}
}
}
<button type="submit">submit</button>
</form>
if you want know reason of using indexer on model i recommend How does MVC 4 List Model Binding work?
Consider if it the responsibility of the view or the controller action to make the decisions - you can send everything back to the action to do the decision making.
In your Views/Shared folder, create a controller called EditorTemplates
In this folder, add a partial view called OtherModel
In this view, set the model to OtherModel and set the Layout=null
Add the three OtherModel fields in EditorFor (and HiddenFor if not displaying isPropTrue). This partial view displays just one instance of your list.
In your main view, use the above editor model like so. MVC will take care of all rendering and postback of the Model State for your complete list of items. We like one-liners...
#Html.EditorFor(model => model.OtherModel)
When the data is subsequently posted back to an action, Model State has wrapped up all of your displayed items into a list again, so you can check the isPropTrue value for each item on the server.
The only issue with MVC is that is you pass an empty list out to a view, you get a null value back, so just replace this with an empty list when null is returned

Generate a list of contacts from a table based on a Bool value

I am currently developing an asp.NET MVC web application as a front end to a database. I have a MySQL database, one of the tables is contact information for employees. I have added a column of 'isOnSite' of datatype TINYINT(1).
I have updated the data model in my application, and added a checkbox control for this in one of my view. This works fine, I edit a contact, check the box to say that they are currently contracted to this particular site, and a '1' is populated in the 'isOnSite' column for that particular record, great!
One of the views is a Dashboard. In this view (using a partial view) I would like to generate a list of the contacts in the table that have the value of 'isOnSite = true'
I am struggling to do this. I should mention that I am pretty new to all of this.
Any help would be greatly appreciated.
Thank you in advance!
-- EDIT --
With the help of #Bunnynut and also my Father-in-Law We managed to solve this,
in large part to the code examples by #Bunnynut.
CONTROLLER ACTION
public ViewResult Index()
{
var tblcontacts = from m in db.tblcontacts.Where(x => x.isOnSite)
select m;
return View(tblcontacts.OrderBy(x => x.LastName).ToList());
}
PARTIAL VIEW
#model IEnumerable<ResourceBase.Models.tblcontact>
#{
ViewBag.Title = "OnSite";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>OnSite</h2>
<div class="container-fluid-viewport jumbotron col-xs-offset-4">
#foreach (var x in Model)
{
#x.FullName <br />
}
</div>
And the Main view just renders the partial view.
Thanks again for your help #Bunnynut
To begin with the Index View uses a model of type ResourceBase.Models.tlbcontact which is it seems a single tblcontcat.
But you are try to pass a List to your partial view so that is not possible.
You Index View should consume a model of which it pass parts of it to your partial views.
IndexViewModel:
public class IndexViewModel
{
public string Title { get; set; }
public List<ResourceBase.Models.tblcontact> Employees { get; set; }
}
Index Action:
public ActionResult Index()
{
var model =
new IndexViewModel
{
Title = "PeopleBase Dashboard",
Employees = GetEmployees()
};
return View(model);
}
Index View:
#model IndexViewModel
<div class="container-fluid-viewport col-md-offset-3 col-md-9">
<h2>#Model.Title</h2>
<div class="partialViewWrapper jumbotron">#{Html.RenderPartial("_peopleBaseDashView", Model.Employees.Where(x => x.isOnSite).ToList());}
</div>
</div>
Your partial View looks ok to me
Use the following SELECT statement
SELECT * FROM yourTable WHERE isOnSite = 1
to fill a property of your ViewModel, which you can then display in your view.
You can easily pass the list of employees directly to your partial view as long as you tell your partial view the model passed is of that type.
So in the master view containing the code that call the partial view you can do this:
#{Html.RenderPartial("NAME_PARTIAL_VIEW", employees.Where(x => x.isOnSite).ToList());}
And in you partial view:
#model List<Employee>
#foreach(var employee in Model)
{
#employee.Name
}

How to pass back model to controller using razor dropdownlist

I have a DropDownListFor control that I am wanting to show a display value that resides in a property within a model/class (this is the Rule class.) The view's model is actually a collection of these model/classes. However, when I select the item from the DropDownList, I want to send back the entire model as a parameter. I have this working perfectly with the following code, but the Name property within the parameter is coming back as null. The other properties all have appropriate values.
View Code:
#model List<StockTrader.Web.Data.Rule>
#{
ViewBag.Title = "Configure Rules";
}
<h2>#ViewBag.Title</h2>
<h4>Choose a rule to edit:</h4>
<form method="post" id="rulesform" action="SaveRules">
#Html.DropDownListFor(m => m.First().RuleID, new SelectList(Model.AsEnumerable(), "RuleID", "Name"))
<div style="margin-bottom: 15px;">
<label>Value:</label><br />
<input type="number" name="Value" style="margin-bottom: 15px;" /><br />
<button>Save Value</button>
</div>
Controller Code:
public ActionResult SaveRules(Rule model)
{
//do something
}
Rule Class:
public class Rule
{
public int RuleID { get; set; }
public string Name { get; set; }
public int Value { get; set; }
public bool IsDeleted { get; set; }
}
We do have Kendo controls, so if another control would be more appropriate, that is an option.
I would be glad to provide anymore code or information you might need.
Any thoughts or ideas?
EDIT:
So it turns out this is what I needed to do, the accepted answer got me to this point so I'm going to leave it checked.
View Code (w/script included):
#Html.DropDownListFor(m => m.First().RuleID, new SelectList(Model.AsEnumerable(), "RuleID", "Name"), new { id = "ruleid", #onchange = "CallChangefunc(this)" })
#Html.HiddenFor(m => m.First().Name, new { id = "rulename" })
function CallChangefunc(e) {
var name = e.options[e.selectedIndex].text;
$("#rulename").val(name);
}
You will need a hidden field for it,and use dropdownlist on change event on client side to update hidden field:
#Html.DropDownListFor(m => m.First().RuleID, new SelectList(Model.AsEnumerable(), "RuleID", "Name"),new { id= "ruleid" })
#Html.HiddenFor(m=>m.First().Name,new { id="rulename" })
and jquery code:
$("#ruleid").change(function(){
$("#rulename").val($(this).text());
});
Second option isif Rule collection is coming from database you can fetch RuleName by using id to by querying db in action.
it can be achieved by using UIHint
On your model class, on the RuleID property, add an annotation for UIHint. It basically lets you render a partial (cshtml) for the property. So, on the partial, you can have the template for generating the dropdwon with required styling. When Page is generated. Now you can use the same Html.DropDownListFor for RuleID and UI generates a dropdown for it.
This will avoid having additional jQuery code to get the dropdown value, and code is more concise and testable.

Update a Model and a Collection of Models on a Single View (MVC4)

I've been working on an MVC 4 Application and have run into a problem when attempting to update Models in a ViewModel.
My ViewModel (detailed below) contains one ComplexObjectOne and a List<ComplexObjectTwo>.
My GET ActionResult successfully populates the ViewModel from a database and everything displays correctly on my View.
The problem is encountered when attempting to pass the ComplexObjectOne and List<ComplexObjectTwo> to the POST ActionResult.
The ComplexObject is passed correctly but everything I've tried fails pass the List<ComplexObjectTwo> collection.
My ComplexModelOne Model
public class Test
{
public int Id {get;set;}
public string Result {get;set;}
public virtual ICollection<TestResult> TestResults {get;set;}
}
My ComplexModelTwo Model
public class TestResult
{
public int Id {get;set;}
public string Result {get;set;}
public string Comment {get;set;}
public virtual Test Test{get;set;}
}
My ViewModel
public class TestingViewModel
{
public TestingViewModel()
{
if(TestResults == null)
{
TestResults = new List<TestResult>();
}
}
public Test Test {get;set;}
public IEnumerable<TestResult> TestResults {get;set;}
}
My Edit() GET ActionResult
public ActionResult Edit(int id = 0)
{
var viewModel = new TestingViewModel();
Test test = testRepo.GetTestById(id);
var results = test.TestResults;
viewModel.Test = test;
viewModel.TestResults = results;
return View(viewModel);
}
My Edit() POST ActionResult
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(TestingViewModel model)
{
// do update - left out for brevity
}
My Edit.cshtml View
#model Namespace.Models.ViewModels.TestingViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.EditorFor(model => model.Test, "TestHeader")
<table>
<tr>
<th>Test</th>
<th>Result</th>
<th>Comment</th>
</tr>
#Html.EditorFor(model => model.TestResults, "TestResults")
</table>
<input type="submit" value="Update"/>
}
Within my View I do use a couple of EditorTemplates to display the property fields.
Any assistance, comments, or suggestions will be much appreciated. I'd like to be able to accomplish updating these entities on a single page instead of multiple pages which I resorted to in the Create() steps.
Thank you,
Patrick H. (stpatrck)
Replace:
#Html.EditorFor(model => model.TestResults, "TestResults")
with:
#Html.EditorFor(model => model.TestResults)
and then rename your EditorTemplates/TestResults.cshtml editor template to EditorTemplates/TestResult.cshtml (notice the missing s) and inside replace the model declaration from:
#model IEnumerable<TestResult>
to:
#model TestResult
Now obviously this will lead to getting rid of any for or foreach loops you might have written in this editor template because now ASP.NET MVC will automatically invoke the template for each element of the collection.
So for example:
#foreach (var item in Model)
{
#Html.EditorFor(x => item.SomeProperty)
}
will simply become:
#Html.EditorFor(x => x.SomeProperty)
Now look at the generated markup and notice the difference in the names of your input fields. Before you had:
<input type="text" name="item.SomeProperty" value="foo" />
and now you have:
<input type="text" name="TestResults[0].SomeProperty" value="foo" />
Now when you submit the form to the POST action the default model binder will be able to successfully bind the collection because now the naming convention is respected. You can read more about this convention in the following blog post.
Also you have circular references in your object graph which cannot be successfully serialized and model bound. You should use view models in order to break this circular dependency.

DropDown not displaying what was previously selected & saved

The customer can view their cust details page where they can change their pre-recorded delivery run (if they wish too) I have a drop down list containing towns for delivery runs:
<div class="editor-label">#Html.DropDownListFor(model => model.DeliveryRunList, Model.DeliveryRunList)</div>
When the customer profile loads it displays the correct town in the drop down(reading from the DB, which they previously selected when registering).
However if they change the town and save it, the user is returned to the home page and the newly selected tow is saved to the DB. But, if the user returns to the customer profile page the drop down displays the previously selected town, as opposed to the new one just previously selected and saved to the DB. Is it being stored in the cache somewhere.
Why is it not updating to what is actually in the DB??
Codebehind:
CustomerPart custPart = _custService.Get(custId);
if (DeliveryRunList.HasValue)
{
custPart.DeliveryRun_Id = DeliveryRunList.Value;
}
_custService.Update(custPart);
Thanks
I suppose model is a CustomerPart instance, and you have defined it more or less in this way.
public class CustomerPart
{
public int DeliveryRun_Id {get; set;}
public SelectList(or some IEnumerable) DeliveryRun_Id
}
I feel your code isn't updating the DB since you use the wrong attributes. The first lambda expression should be model => model.TheAttributeYouWantToUpdate, in this case DeliveryRun_Id.
So it should be:
#Html.DropDownListFor(model => model.DeliveryRun_Id, Model.DeliveryRunList)
rather than
#Html.DropDownListFor(model => model.DeliveryRunList, Model.DeliveryRunList)
It's not even clear where is this code inside the controller:
CustomerPart custPart = _custService.Get(custId);
if (DeliveryRunList.HasValue)
{
custPart.DeliveryRun_Id = DeliveryRunList.Value;
}
_custService.Update(custPart);
A common way of doing it is to have two methods of the same name for editing, one for HttpGet and one for HttpPost, and use a #Html.BeginForm() in the razor view for updating, rather than updating the info in controller.
Example:
public ActionResult Edit(int id = 0) {
InvestmentFund Fund = InvestmentFundData.GetFund(id);
return Fund == null ? (ActionResult)HttpNotFound() : View(Fund);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(InvestmentFund Fund)
{
if (ModelState.IsValid)
{
InvestmentFundData.Update(Fund);
return RedirectToAction("List");
}
return View(Fund);
}
In View
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#* For the attributes of your model *#
#Html.LabelFor ...
#Html.EditorFor ...
#Html.ValidationMessageFor ...
<input type="Submit"m value="Save">
}

Categories

Resources