Only using part of a model losing data.

Roger Porter 41 Reputation points
2022-01-05T16:11:57.42+00:00

Hi,

I have a large model and two views. One view uses some of the model properties and view two uses the rest. My problem is if I add data in view one and then add data in view two, view one's data is lost. I am guessing it is because the properties a view does not use has no where to store them so when the model is return those properties are empty. When I have one or two properties I create hidden fields for the properties I don't use and this works but in this instance there is around 20 properties not used.

I am not sure if I should create to view modals, one with properties for view one and the second having properties for view two and pass them to the view.

I am no expert at ASP..Net Core MVC so don't know the best practise.

Many thanks for any help,

Developer technologies ASP.NET ASP.NET Core
{count} votes

Accepted answer
  1. Anonymous
    2022-01-11T07:54:55.387+00:00

    Hi @Roger Porter ,

    I do a submit on view one which then saves the data to the database. When I load that same row up and pass it to view two it has my data from view one. The problem is in view two I don't use all the properties that view one used. When I do a submit on view two all the properties that are not used and that was populated in view one are blank or null. I am guessing because those properties are not bound to any controls so on the client side there is no way of storing them.

    You are right. When we submit the form to action method, it will based on the form elements to bind the model/parameter, if you haven't bound the property (the property used in view one) in the View two, after click the submit button, in the View two's post method, these properties will be null.

    To prevent this behavior, on the view to get action method, you can get the view one data from the database, then, return the data to View two, in the view page, use a hidden field to store these properties, after that, when you click the submit button, you can get these hidden properties in the View two post method.

    Refer to the following sample code:

    Here I have a Employee class:

    public class Employee  
    {  
        [Key]  
        public int EmpID { get; set; }  
        public string LastName { get; set; }  
        public string FirstName { get; set; }  
        public string Title { get; set; }  
        public string TitleOfCourtesy { get; set; }  
        public DateTime BirthDate { get; set; }  
        public DateTime HireDate { get; set; }  
        public string Address { get; set; }  
        public string City { get; set; }  
        public string Region { get; set; }  
        public string Country { get; set; }  
        public string HomePhone { get; set; }   
    }  
    

    In the controller, create action for the two views:

    public class HomeController : Controller  
    {   
        private readonly ApplicationDbContext _context;  
        public HomeController(ApplicationDbContext applicationDbContext )  
        {   
            _context = applicationDbContext;  
        }  
    
        public IActionResult CreateEmployeeOne()  
        {  
            return View();  
        }  
        [HttpPost]  
        public IActionResult CreateEmployeeOne( Employee employee)  
        {  
            if (!ModelState.IsValid)  
            {  
                return View(employee);  
            }  
            _context.Employees.Add(employee);  
            _context.SaveChanges();  
    
            //redirect to view two and transfer the new employee id to the view two.  
            return RedirectToAction(nameof(CreateEmployeetwo), new { empid = employee.EmpID });  
        }  
        [HttpGet]  
        public IActionResult CreateEmployeetwo(int empid)  
        {  
            var employee = new Employee();  
            if (empid != 0)  
            {  
                //based on the id to find the employees from database.  
                employee  = _context.Employees.First(c => c.EmpID == empid);  
            }   
            return View(employee);  
        }  
        [HttpPost]  
        public IActionResult CreateEmployeetwo(Employee employee)  
        {  
            return View();  
        }  
    

    Then, in the view one (CreateEmployeeOne.cshtml) form tag, only display the first name and last name:

    @model CoreMVC5Sample.Models.Employee  
    <div class="row">  
        <div class="col-md-4">  
            <form asp-action="CreateEmployeeOne">  
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>   
                <div class="form-group">  
                    <label asp-for="LastName" class="control-label"></label>  
                    <input asp-for="LastName" class="form-control" />  
                    <span asp-validation-for="LastName" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="FirstName" class="control-label"></label>  
                    <input asp-for="FirstName" class="form-control" />  
                    <span asp-validation-for="FirstName" class="text-danger"></span>  
                </div>   
                <div class="form-group">  
                    <input type="submit" value="Create" class="btn btn-primary" />  
                </div>  
            </form>  
        </div>  
    </div>  
    

    In the View two (CreateEmployeetwo.cshtml): we can use the hidden filed control or add hidden attribute on the html elments.

    @model CoreMVC5Sample.Models.Employee  
    <div class="row">  
        <div class="col-md-4">  
            <form asp-action="CreateEmployeetwo">  
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>  
                <div class="form-group">  
                    <label asp-for="EmpID" class="control-label"></label>  
                    <input asp-for="EmpID" class="form-control" />  
                    <span asp-validation-for="EmpID" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="LastName" class="control-label"></label>  
                    <input asp-for="LastName" class="form-control" />  
                    <span asp-validation-for="LastName" class="text-danger"></span>  
                </div>  
                <div class="form-group" hidden>  
                    <label asp-for="FirstName" class="control-label"></label>  
                    <input asp-for="FirstName" class="form-control"  />  
                    <span asp-validation-for="FirstName" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="Title" class="control-label"></label>  
                    <input asp-for="Title" class="form-control" />  
                    <span asp-validation-for="Title" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="TitleOfCourtesy" class="control-label"></label>  
                    <input asp-for="TitleOfCourtesy" class="form-control" />  
                    <span asp-validation-for="TitleOfCourtesy" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="BirthDate" class="control-label"></label>  
                    <input asp-for="BirthDate" class="form-control" />  
                    <span asp-validation-for="BirthDate" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="HireDate" class="control-label"></label>  
                    <input asp-for="HireDate" class="form-control" />  
                    <span asp-validation-for="HireDate" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="Address" class="control-label"></label>  
                    <input asp-for="Address" class="form-control" />  
                    <span asp-validation-for="Address" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="City" class="control-label"></label>  
                    <input asp-for="City" class="form-control" />  
                    <span asp-validation-for="City" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="Region" class="control-label"></label>  
                    <input asp-for="Region" class="form-control" />  
                    <span asp-validation-for="Region" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="Country" class="control-label"></label>  
                    <input asp-for="Country" class="form-control" />  
                    <span asp-validation-for="Country" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <label asp-for="HomePhone" class="control-label"></label>  
                    <input asp-for="HomePhone" class="form-control" />  
                    <span asp-validation-for="HomePhone" class="text-danger"></span>  
                </div>  
                <div class="form-group">  
                    <input type="submit" value="Create" class="btn btn-primary" />  
                </div>  
            </form>  
        </div>  
    </div>  
    

    The result is like this: as we can see that, after click the submit button in the view one, in its post method, we can see only the first name and last name has value:

    163747-1.gif

    Note: In the above sample, we should follow the order to create an employee: click the view one first (to enter the first name and last name) and then click the submit button in view one, it will redirect to view two, then we can enter other properties.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Dillion

    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2022-01-05T20:57:07.57+00:00

    the view models are to shared between pages. on a get action, the view model is used to pass data from the controller to the view to the view. on a form post, the form data bound is bound to the view model in the action parameter list. then this view model, is typically used by the action.

    in the standard get-post-get pattern, the post would redirect to a get action that displayed a new view. as the mvc app is stateless (no data shared between request), you need to decide how data is passed from one page to another. typically some sort of server state (database) is used.

    0 comments No comments

  2. Roger Porter 41 Reputation points
    2022-01-06T10:12:32.357+00:00

    Thank you all for your reply's. I have two individual views that are called from a menu bar at the top of my layout page. What is happening is one view only uses part of the model so when the post occurs all properties that are not used are initialised to either zero or null. Those properties could have been filled from the second view thus losing data. I ended up using <input type="hidden" asp-for="customer....." /> for each of the properties not being used in the views. I am not sure if this is correct or not.

    Really I suppose I should normalise the data. The reason this hasn't happened is because the second view was added later on and it would be a big job to to.

    Thanks again,


  3. AgaveJoe 30,126 Reputation points
    2022-01-07T18:58:13.137+00:00

    Since the data submitted from the first view is inserted into the database there is no need to cache the same data in hidden fields or session. In the action that inserts the record, do a RedirectToAction() with the newly created Id as the route parameter. The next action reads the route Id and uses the Id to fetch the data from the database.

    int Id = 1;  //Get the ID from the newly created record.  
    return RedirectToAction("Index", "Home", new { id = Id });  
    

    Routing to controller actions in ASP.NET Core

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.