DropDown not displaying what was previously selected & saved - c#

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">
}

Related

Data Binding in ASP.NET MVC

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.

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 display assosiated data on second tab based on the data coming under first tab in ASP.NET MVC and EF

I am using MVC application and entityframework,i have two table country and city which has PK_FK relation ship.In my UI i am using two tabs, first tab for countries and second for cities and both are displayed in a grid which is in two partial views.Now what i have to achieve is if i click a country in first tab corresponding country cities should display in second tab rather than complete country cities.How to do that following is the existing code i have done
controller
public ActionResult Index()
{
return View();
}
public ActionResult _gridfirsttab()
{
return PartialView(db.Countries.ToList());
}
public ActionResult _gridsecondtab()
{
return PartialView(db.Citynews.ToList());
}
Index view
<ul>
<li>Tab Header 1</li>
<li>#Html.ActionLink("Tab Header 2", "_gridsecondtab")</li>
<li>>#Html.ActionLink("Tab Header 3", "_gridthirdtab")</li>
</ul>
<div id="tabs-1">
#Html.Action("_gridfirsttab")
</div>
UPDATE
I did like shown below but it is duplicating webgrid, may HTTPGET action also triggering how to prevent it
first partial view grid
#if (grid.HasSelection)
{
conuntry = (firstmvc4.Models.Country)grid.Rows[grid.SelectedIndex].Value;
#Html.Action("_gridsecondtab", new {id =conuntry.id })
}
and created one more HTTPPOST action of first grid
[HttpPost]
public ActionResult _gridsecondtab(int id)
{
// Find the customer by name
var countries = db.Countries.FirstOrDefault(c => c.id == id);
// Get the customers products
var cities = countries.Citynews;
// Send products to the View to be rendered
return PartialView(cities);
}
But it is not properly working rather duplicating first grid itself

C# MVC add records to related table from one view

The background for my C# knowledge is 0. I am trying to learn it as I go. I just am not sure how to use the right words to search. So I am crying for help !
I have a small ASP.Net Web application that uses MVC framework. I have a Database which hold three tables Company, Territory, the third is a relationship table TerritoryCompany. So the basic set up is one Company can have branches in several Territory, and one Territory can have several Company. The relationship is Many-Many.
What I have is a CS Code that will allow you to create a company, nothing fancy, just
public void Save(CompanyModel company)
{
using (var db = new SampleDbContext())
{
Company entity;
if (company.CompanyId > 0)
{
entity = db.Companies.First(x => x.Id == company.CompanyId);
}
else
{
entity = new Company();
db.Companies.Add(entity);
}
entity.Name = company.CompanyName;
entity.PhoneNo = company.PhoneNo;
//What should I do?
db.SaveChanges();
}
}
Now as you see, I am able to add the Company Name and Phone Number. Good. This is the code I use in the Webpage,
#model PEF.SampleTesting.Domain.CompanyModel
#{
ViewBag.Title = "Add";
}
#using (Html.BeginForm("Save", "Companies"))
{
#Html.EditorForModel()
<label>Enter the list of service area</label><br />
<input id="ServiceArea" class="form-control" name="testBox" value="eg. BS1, BA5" /><br/>
<button type="Submit" class="btn btn-primary">Save</button>
}
Here is the CompaniesController
[HttpPost]
public ActionResult Save(CompanyModel model)
{
if (!ModelState.IsValid) return View((model.CompanyId == 0)?"Add":"Edit", model);
_companyService.Save(model);
return RedirectToAction("Index");
}
What I would like to do is, before doing the save changes db.SaveChanges(); when the company is created, I would like to
Add these entries for the Territory - if the territory does not exist in the Territory table
or
Create an entry in the relationship table for that CompanyID and the corresponding TerritoryID) for that particular Company.
I created a TextBox that will get a comma separated entry of territories. Use this TextBox value in a For and create as many entities to the table Territory (using for loop and split function maybe).
My Questions;
How would I pass the form value (TextBox) back to the code?
How can I use the For Loop to add this 'n' number of entries to the TerritoryCompany table?
Any helps or steps would be greatly appreciated.
Typically instead of passing your data entities to your view you would create a viewmodel, that will provide you with more flexibility...
Something like this class "AddCompanyViewModel", it has a property for your Company and also a property for your comma separated string of territories...
You will now pass this viewmodel too and from your controller instead of the entity type... this is a common scenario as your database structure will rarely perfectly match your domain layer (business layer)... view models essentially model your view.
public class AddCompanyViewModel
{
public CompanyModel Company { get; set; }
public string Territories { get; set; }
}
[HttpPost]
public ActionResult Save(AddCompanyViewModel model)
{
if (!ModelState.IsValid)
return View((model.Company.CompanyId == 0)?"Add":"Edit", model);
_companyService.Save(model.Company);
// Do something with territories...
var territories = model.Territories.Split(',');
return RedirectToAction("Index");
}
You can use the FormCollection parameter for the action.
public ActionResult Save(CompanyModel model, FormCollection formCol)
Reference the textbox via the name property.
Not quite sure about what you're asking for. You can use the Foreach loop to loop through each territory after you've split the textbox value. Then you create your TerritoryCompany model and save accordingly.

NullReference error on foreach used to create radiobuttons on POST

I am teaching myself asp .net mvc3. I have a "add property" form which allows user to upload property details to the website. I have been struggling with this error for a long time now.
For simplification, lets consider that I have two tables in my database.
CustomerTypes: The database has 1 Owner, 2 Broker, 3 Commercial etc
Property: This is the table that gets populated by the form.
I use CustomerTypes (and other such tables) to create radio buttons. The user fills the form and selects a choice for "customer type". However, I get an "object reference not set to an instance of an object" error on submit. This is is because "null" is
set for Model.CustomerTypes. However, Model.CustomerTypes is only used to create radio buttons. I am not sure what is wrong. The code is below:
View:
#model Website.ViewModels.AddPropertyViewModel
<fieldset>
<legend>Property</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Property.CustomerType)
#foreach (var item in Model.CustomerTypes)
{
#Html.RadioButtonFor(model => model.Property.CustomerType, Convert.ToInt32(item.Value)) #item.Text
}
</div>
...
AddPropertyViewModel:
namespace Website.ViewModels
{
public class AddPropertyViewModel
{
public Property Property { get; set; }
...
public IEnumerable<SelectListItem> CustomerTypes { get; set; }
...
}
Controller:
public ActionResult AddProperty()
{
AddPropertyViewModel viewModel = new AddPropertyViewModel
{
...
CustomerTypes = websiterepository.GetCustomerTypeSelectList(),
...
};
return View(viewModel);
GetCustomerTypeSelectList functions is:
public IEnumerable<SelectListItem> GetCustomerTypeSelectList()
{
var customerTypes = from p in db.CustomerType
orderby p.CustomerTypeDescription
select new SelectListItem
{
Text = p.CustomerTypeDescription,
Value = SqlFunctions.StringConvert((double)p.CustomerTypeId)
};
return customerTypes;
}
The value in POST is set for Property_CustomerType correctly based on the selection
--- Added further info ---
I start the form as:
#using (Html.BeginForm("AddProperty", "Property", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
}
The controller is:
[HttpPost]
public ActionResult AddProperty(AddPropertyViewModel viewModel)
{
if (ModelState.IsValid)
{
//
if (viewModel.File1.ContentLength > 0)
{
var fileName = Path.GetFileName(viewModel.File1.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data"), fileName);
viewModel.File1.SaveAs(path);
}
var property = viewModel.Property;
websiterepository.Add(property);
return RedirectToAction("Index", "Home");
}
return View(viewModel);
}
Here is a screenshot of error:
I have tried submitting the form commenting these radio buttons and it works.
The issue is that CustomerTypes isn't populated when your render the view after posting to the server.
If we look at the flow of actions being performed we see that
You populate the CustomerTypes collection before rendering the
inital page
You post your data back to the server but do not
preserve the CustomerTypes collection (Because there's no need to)
You render the view again but this time without populating
CustomerTypes.
Kaboom!
Populating the CustomerTypes property before you return the view for the second time should fix your problem:
[HttpPost]
public ActionResult AddProperty(AddPropertyViewModel viewModel)
{
[...]
viewModel.CustomerTypes = websiterepository.GetCustomerTypeSelectList();
return View(viewModel);
}

Categories

Resources