I'm working on a ASP.NET Core webpage using Razor Pages. On one page, a customer is added or selected and the customer_id is passed through correctly in the OnGet function (seen through debugging). When I then have the user fill out the form, I try to make a call to a SQL server database using Entity Framework. Everything should be working correctly, however, in OnPostAsync(), when I try to import the customer_id value I had set in OnGet(), I get an error because the value somehow gets set to 0 instead of what I had it previously set as. I don't know why this is happening as I'm generally new to Razor Pages and Entity Framework, but I've posted the code below. Any suggestions would be great!
AddAssessment.cshtml.cs:
namespace CustomerPageTest.Pages.Assessment
{
public class AddAssessmentModel : PageModel
{
private readonly CustomerPageTest.Data.CustomerPageTestContext _context;
public AddAssessmentModel(CustomerPageTest.Data.CustomerPageTestContext context)
{
_context = context;
}
public static List<SelectListItem> InDatabaseUserData()
{
List<SelectListItem> Users = new List<SelectListItem>();
string connString = "Data Source = DESKTOP-5A23I9M; Initial Catalog = DataWarehouse; User ID = sa; pwd = 2128Swan";
string commandString = "SELECT user_id, name FROM KelderUser";
SqlConnection conn = new SqlConnection(connString);
SqlDataAdapter adapter = new SqlDataAdapter(commandString, conn);
DataTable dtCustomers = new DataTable();
adapter.Fill(dtCustomers);
foreach (DataRow dataRow in dtCustomers.Rows)
{
SelectListItem temp = new SelectListItem()
{
Value = dataRow[0].ToString(),
Text = dataRow[1].ToString()
};
Users.Add(temp);
}
return Users;
}
[BindProperty]
public CustomerPageTest.Assessment Assessment { get; set; } = new CustomerPageTest.Assessment();
public List<SelectListItem> SelectUser { get; set; } = new List<SelectListItem>();
public void OnGet(int customerId)
{
SelectUser = InDatabaseUserData();
Assessment.customer_id = customerId;
if(Assessment == null)
{
return RedirectToPage("/Customer/List");
}
return Page();
}
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
foreach(var item in SelectUser)
{
if (item.Selected)
{
try { Assessment.user_id = Convert.ToInt32(item.Value); } catch (Exception) { }
}
}
try { Assessment.imported_data_datetime = Convert.ToDateTime(Assessment.imported_data_datetime); } catch(Exception) { }
_context.Assessment.Add(Assessment);
await _context.SaveChangesAsync();
return RedirectToPage("/Customer/List");
}
}
}
Then AddCustomer.cshtml:
#page
#model CustomerPageTest.Pages.Assessment.AddAssessmentModel
#{
ViewData["Title"] = "AddAssessment";
}
<h1>AddAssessment</h1>
<h4>Assessment</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Assessment.vcenter" class="control-label"></label>
<input asp-for="Assessment.vcenter" class="form-control" />
<span asp-validation-for="Assessment.vcenter" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Assessment.imported_data_datetime" class="control-label"></label>
<input asp-for="Assessment.imported_data_datetime" class="form-control" />
<span asp-validation-for="Assessment.imported_data_datetime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Assessment.notes" class="control-label"></label>
<input asp-for="Assessment.notes" class="form-control" />
<span asp-validation-for="Assessment.notes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Assessment.user_id"></label>
<select class="form-control" asp-for="Assessment.user_id" asp-items="Model.SelectUser">
<option value="">Select a User</option>
</select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="/Customer/List">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Also, If you have any questions about what is going on in my code, let me know as there are other classes and pages before this. The main idea is that I have an Assessment class with an integer: customer_id, that needs to be set and it's not getting set.
I write a demo,and i find you didn't bind the customer_id in the cshtml,so when you post the date to cshtml.cs,you didn't post the customer_id.You can add <input hidden asp-for="Assessment.customer_id" class="form-control" /> in the cshtml to bind customer_id.
Here is a demo worked:
cshtml:
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Assessment.vcenter" class="control-label"></label>
<input asp-for="Assessment.vcenter" class="form-control" />
<span asp-validation-for="Assessment.vcenter" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Assessment.imported_data_datetime" class="control-label"></label>
<input asp-for="Assessment.imported_data_datetime" class="form-control" />
<span asp-validation-for="Assessment.imported_data_datetime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Assessment.notes" class="control-label"></label>
<input asp-for="Assessment.notes" class="form-control" />
<span asp-validation-for="Assessment.notes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Assessment.user_id"></label>
<select class="form-control" asp-for="Assessment.user_id" asp-items="Model.SelectUser">
<option value="">Select a User</option>
</select>
</div>
<input hidden asp-for="Assessment.customer_id" class="form-control" />
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
cshtml.cs:
public class AddCustomerModel : PageModel
{
[BindProperty]
public Assessment Assessment { get; set; } = new Assessment();
public List<SelectListItem> SelectUser { get; set; } = new List<SelectListItem>();
public IActionResult OnGet()
{
for (int i = 1; i < 6; i++) {
SelectListItem temp = new SelectListItem()
{
Value = i+"",
Text = "user"+i
};
SelectUser.Add(temp);
}
Assessment.customer_id = 2;
Assessment.vcenter = "vcenter";
return Page();
}
public IActionResult OnPost() {
if (!ModelState.IsValid)
{
return Page();
}
return Page();
}
}
Result:
The reason this happens is because HTTP is stateless. Any state (data) that you created in one request is destroyed once that request has been processed unless you take steps to persist it.
There are multiple ways to manage state in Razor Pages (https://www.learnrazorpages.com/razor-pages/state-management), but in your case, you should use a hidden form field, posting the selected customer ID to the OnPost handler
Related
I have a simple MVC app that is consuming a web api via REST. The controller in the MVC app makes http calls to the web api to populate views within the MVC app with razor syntax.
I am trying to figure out how to populate a drop down list on one of the 'create' actions. I'm currently just using the scaffolded page:
#model ComicBookInventory.Shared.ComicBookWithAuthorsAndCharactersViewModel
#{
ViewData["Title"] = "CreateComicBook";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>CreateComicBook</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="CreateComicBook">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Id" class="control-label"></label>
<input asp-for="Id" class="form-control" />
<span asp-validation-for="Id" 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="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsRead" /> #Html.DisplayNameFor(model => model.IsRead)
</label>
</div>
<div class="form-group">
<label asp-for="DateRead" class="control-label"></label>
<input asp-for="DateRead" class="form-control" />
<span asp-validation-for="DateRead" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Rating" class="control-label"></label>
<input asp-for="Rating" class="form-control" />
<span asp-validation-for="Rating" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CoverUrl" class="control-label"></label>
<input asp-for="CoverUrl" class="form-control" />
<span asp-validation-for="CoverUrl" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
Which gets populated from this action in the controller:
public async Task<IActionResult> CreateComicBook(ComicBookWithAuthorsAndCharactersViewModel model)
{
string uri = $"https://localhost:5001/api/comicbook/add-book/";
HttpClient client = _httpClientFactory.CreateClient(
name: "ComicBookInventory.Api");
var postTask = await client.PostAsJsonAsync<ComicBookWithAuthorsAndCharactersViewModel>(uri, model);
if (postTask.IsSuccessStatusCode)
{
return RedirectToAction("GetAllComics");
}
else
{
return View(model);
}
}
Here is the view model definition:
namespace ComicBookInventory.Shared
{
public class ComicBookWithAuthorsAndCharactersViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool IsRead { get; set; }
public DateTime? DateRead { get; set; }
public int? Rating { get; set; }
public string Genre { get; set; }
public string? CoverUrl { get; set; }
/// <summary>
/// Navigation properties
/// </summary>
/// a book can have many authors
public ICollection<string>? AuthorNames { get; set; }
public ICollection<string>? CharacterNames { get; set; }
}
}
My question is, I want to add a drop down checklist to the view, so that when I am creating a comic book, I can select Authors that currently exist in the database. The same for characters.
Here is the entire code base in case anyone is interested: https://github.com/rnemeth90/ComicBookInventoryApp
I normally try and figure things out on my own (I'm relatively new to EF Core, and have very little experience with many-to-many relationships in EF core). I have tried various things and struggled with this for most of my weekend. I feel like this should be relatively simple but cannot figure it out. Please help.
In your Code, I noticed that you used #Html.DropDownList to realzie the selector element, and using form submit to handle the data. So I did a test in my side:
#{
List<SelectListItem> listItems= new List<SelectListItem>();
listItems.Add(new SelectListItem
{
Text = "Exemplo1",
Value = "Exemplo1_v"
});
listItems.Add(new SelectListItem
{
Text = "Exemplo2",
Value = "Exemplo2_v",
Selected = true
});
listItems.Add(new SelectListItem
{
Text = "Exemplo3",
Value = "Exemplo3_v"
});
}
<form asp-action="Create">
<div class="form-group">
AuthorNames
<div class="col-md-10">
#Html.DropDownListFor(model => model.Author, listItems, "-- Select author --")
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
My model contains a public string? Author { get; set; } property, and when I click the submit button, the select value will be submitted, so when you want to pass the FullName to your controller, you need to set it as the Value of the SelectListItem.
below my html code
<div class="border backgroundWhite border-info">
<div class="row">
<div class="col-6">
<div class="form-group row">
<div class="col-4">
<label asp-for="Shift.TSBalance"></label>
</div>
<div class="col-6">
<input asp-for="Shift.TSBalance" class="form-control" id="sbalance" readonly value="#Model.V" onkeyup="sum()" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label asp-for="Shift.TSupply"></label>
</div>
<div class="col-6">
<input asp-for="Shift.TSupply" class="form-control" id="supply" value="0" onkeyup="sum()" type="text"/>
</div>
<span asp-validation-for="Shift.TSupply" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-4">
<label asp-for="Shift.TTotal"></label>
</div>
<div class="col-6">
<input asp-for="Shift.TTotal" class="form-control" readonly id="trbalance" value="0" onkeyup="sum()" type="text"/>
</div>
<span asp-validation-for="Shift.TTotal" class="text-danger"></span>
</div>
</div>
<div class="col-6">
<div class="form-group row">
<div class="col-7">
<label asp-for="Shift.TCBalance"></label>
</div>
<div class="col-5">
<input asp-for="Shift.TCBalance" class="form-control" id="calcebalance" value="0" onkeyup="sum()" type="text" readonly/>
</div>
</div>
<div class="form-group row">
<div class="col-7">
<label asp-for="Shift.TABalance"></label>
</div>
<div class="col-5">
<input asp-for="Shift.TABalance" class="form-control" id="actualebalance" value="0" onkeyup="sum()" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-7">
<label asp-for="Shift.TDifferance" class="text-info"></label>
</div>
<div class="col-5">
<input asp-for="Shift.TDifferance" class="form-control" style="background-color:blue;color:white;font-size:larger" id="differance" value="0" onkeyup="sum()" type="text" readonly />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
my page model
namespace Elwady.Pages.ShiftClosing
{
public class CreateModel : PageModel
{
private readonly ApplicationDbContext _db;
public SelectList Exlist { get; set; }
[BindProperty]
public Shift Shift { get; set; }
public CreateModel(ApplicationDbContext db)
{
_db = db;
}
public IActionResult OnGet()
{
this.Exlist = new SelectList(_db.ExpensesList, "Id", "ExName");
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
};
_db.Shift.Add(Shift);
await _db.SaveChangesAsync();
return RedirectToPage("../Index");
}
}
}
my data table
public class Shift
{
public int Id { get; set; }
public int TSBalance { get; set; }
public int TSupply { get; set; }
public int TTotal { get; set; }
public int TCBalance { get; set; }
public int TABalance { get; set; }
public int TDifferance { get; set; }
}
i tried to get this value in variable in Get Handler but i couldn't assign it to page UI
if i need to print out this form after submit to specific printer, how can i do that?
I am new in Asp.Net
<input asp-for="Shift.TABalance" class="form-control" id="actualebalance" value="0" onkeyup="sum()" type="text" />
First, please check the input elements, since you add the value attribute (value="0"), in this scenario, even if the page model Shift contains data, it will display 0, because the value="0" attribute will override the asp-for="Shift.TABalance".
So try to remove the value="0" attribute from the input element.
Then, to get the TABalance entered value and assign it to the TSBalance, you can use the onInput event. code like this:
<div class="col-6">
<input asp-for="Shift.TSBalance" class="form-control" id="sbalance" readonly value="#Model.Shift.TSBalance" onkeyup="sum()" type="text" />
</div>
<div class="col-5">
<input asp-for="Shift.TABalance" class="form-control" id="actualebalance" onkeyup="sum()" oninput="TABalanceInput()" type="text" />
</div>
#section Scripts{
<script>
function sum(){
}
//update sbalance's value when update the actualebalance's value
function TABalanceInput(){
var actualebalance = document.getElementById("actualebalance");
var s = actualebalance.value;
var sbalance = document.getElementById("sbalance");
sbalance.value = s;
}
//after page loaded, trigger the TABalanceInput function and update the actualebalance's value
$(document).ready(function(){
TABalanceInput();
});
</script>
}
The result is like this: after page load, it will trigger the TABalanceInput function to update the value. And if modify the TABalance's value, it will also update the TSBalance's value.
Update:
First, this is the OnGet method in the above sample:
public IActionResult OnGet()
{
//this.Exlist = new SelectList(_db.ExpensesList, "Id", "ExName");
this.Exlist = new SelectList(new List<SelectListItem>()
{
new SelectListItem(){ Value="1", Text="A"},
new SelectListItem(){ Value="2", Text="B"},
new SelectListItem(){ Value="3", Text="C"},
});
// create a new shift, and display them in the view.
Shift = new Shift()
{
Id = 0,
TABalance = 2,
TCBalance = 0,
TDifferance = 0,
TSBalance = 0,
TSupply = 0,
TTotal = 0
};
return Page();
}
i need the last value added to databse in TABalance column retrieved
on TSBalance input box
In previous reply, I create a new Shift to render the data. If you want to get the last added data, you need to soft the shift data and get the last added item, then return it to view page. Refer the following code:
Shift = _db.Shifts.OrderByDescending(c => c.Id).First();
Then, the result is like this:
I'm trying to get a value from each dropdownlist in the view model. I'm doing with a foreach but that doesn't seem to work. Can anyone help me here please?
I'm doing in the controller the foreach. I'm using Entity Framework and repository methods to this. Any help is helpful.
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(int? id, AddSaidasServicoViewModel model, string command)
{
if (ModelState.IsValid)
{
//TODO: adicionar Userhelper para ver quem cria a saida. Criar campo na tabela BD. Ver apontamento Notepad
if (command.Equals("submit1"))
{
await _saidaservicoRepository.AddSaidaServicoAsync(model);
return RedirectToAction(nameof(Create));
}
else
{
foreach(var elementoId in model.Elementos )
{
await _elementoRepository.UpdateElementoSaidaServicosAsync(model);
}
}
return RedirectToAction(nameof(Index));
}
return View(model);
}
View markup:
#model FireHouseGest.web.Models.AddSaidasServicoViewModel
#{
ViewData["Title"] = "Create";
}
<h2>Criar</h2>
<h4>Saída Serviço</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="container">
<div class="row">
<div class="text-center">
<div class="col-md-3 text-center">
<div class="form-group">
<label asp-for="ServicoId" class="control-label"></label>
<select asp-for="ServicoId" asp-items="Model.Servicos" class="form-control"></select>
<span asp-validation-for="ServicoId" class="text-danger"></span>
</div>
</div>
<div class="col-md-3 text-center">
<div class="form-group">
<label asp-for="ViaturaId" class="control-label"></label>
<select asp-for="ViaturaId" asp-items="Model.Viaturas" class="form-control"></select>
<span asp-validation-for="ViaturaId" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<input type="submit" name="command" value="submit1" class="btn btn-default" />
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-group">
<input type="submit" name="command" value="submit2" class="btn btn-default" />
</div>
</div>
<div class="form-group">
<label asp-for="Adecorrer" class="control-label"></label>
<input asp-for="Adecorrer" class="form-control" />
<span asp-validation-for="Adecorrer" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Inicio" class="control-label"></label>
<input asp-for="Inicio" class="form-control" />
<span asp-validation-for="Inicio" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Fim" class="control-label"></label>
<input asp-for="Fim" class="form-control" />
<span asp-validation-for="Fim" class="text-danger"></span>
</div>
</form>
</div>
</div>
ViewModel
namespace FireHouseGest.web.Models
{
public class AddSaidasServicoViewModel
{
public int SaidaServicoId { get; set; }
[Display(Name = "Elementos")]
public int ElementoId { get; set; }
public IEnumerable<SelectListItem> Elementos { get; set; }
[Display(Name = "Viatura")]
public int ViaturaId { get; set; }
public IEnumerable<SelectListItem> Viaturas { get; set; }
[Display(Name = "Serviço")]
public int ServicoId { get; set; }
public IEnumerable<SelectListItem> Servicos { get; set; }
[Display(Name = "Estado")]
public int Adecorrer { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy hh:mm }", ApplyFormatInEditMode = false)]
public DateTime Inicio { get { return DateTime.Now; } }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy hh:mm }", ApplyFormatInEditMode = false)]
public DateTime? Fim { get; set; }
public User user { get; set; }
}
}
This is what I have. Open to suggestions.
Before coding, you need know the following things:
1.Model Binding find and bind the property by matching the name of the input.
2.If you have multiple inputs with the same name, you need set a List<T> type parameter to receive all the values.
3.Dropdownlist gets the selected option value(not text),be sure the type of the value is the same with the type of matched property. (e.g. ElementoId is int type,so the value of each SelectListItem in Elementos should be int or it could be converted to int):
var model = new AddSaidasServicoViewModel()
{
Elementos = new List<SelectListItem>() {
new SelectListItem() { Value = "1", Text = "Elementos1" },
new SelectListItem() { Value = "2", Text = "Elementos2" },
new SelectListItem() { Value = "3", Text = "Elementos3" }
},
//....
};
4.Dropdownlist selected value will match the property by searching the same name of the asp-for="xxx". (e.g. asp-for="ElementoId" will generate html:id="ElementoId" name="ElementoId",so this input value will match the property ElementoId in your model)
5.Although you have two submit button, but the submit button will always submit all the input values which they are in the same form.
Change your code like below and you will receive all the selected ElementoId values in List<string> ElementoId:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(int? id, AddSaidasServicoViewModel model,
List<string> ElementoId, string command)
{
if (ModelState.IsValid)
{
//TODO: adicionar Userhelper para ver quem cria a saida. Criar campo na tabela BD. Ver apontamento Notepad
if (command.Equals("submit1"))
{
//...
}
else
{
foreach (var elementoId in ElementoId)
{
//....
}
}
return RedirectToAction(nameof(Index));
}
return View(model);
}
Thanks Rena for answer. this was what i did.
public async Task UpdateElementosSaidasAsync(AddSaidasServicoViewModel model, List<string> Elementos)
{
int SaidaServicos = _context.SaidaServicos.Max(item => item.Id);
var Saida = await _context.SaidaServicos.FindAsync(SaidaServicos);
if (Elementos == null)
{
return;
}
else
{
foreach (var elementoId in Elementos)
{
var updateElementoSaida = _context.Elementos.Where(e => e.Id == Convert.ToInt32(elementoId)).FirstOrDefault();
updateElementoSaida.saidaServico = Saida;
await _context.SaveChangesAsync();
}
}
return;
}
Is my ViewModel flow right? The 'SubObjectViewModel' class usage is a bad or a good practice? Or should I try other option, like creating a ViewModel only to this class?
And also, how should I return the ViewModel 'ObjectViewModel' to the controller with all its values, change them and refresh values from page view?
My ViewModel
Public class ObjectViewModel{
public string name { get; set; }
public int value { get; set; }
public bool IsCameraPermited { get; set; }
public List<SubObjectViewModel> choosenSubObjects{ get; set; } // need to get it back on controller;
public class SubObjectViewModel
{
public int IdObject { get; set; }
public string Name { get; set; }
public string Config { get; set; }
}
public List<Object> listSub{ get; set; } //list that will be filled on 'Create' Controller
}
My Controller
public IActionResult Create(int id)
{
List<Object> listSubObject = new List<Object>();
listSubObject = _getAllSubObjectsDAO.ListByID(id);
List<Object> choosenObjects= new List<Object>();
choosenObjects = _getChoosenObjectsDAO.ListByID(id);
List<SubObjectViewModel> listSubObject = new List<SubObjectViewModel>();
foreach (Object item in choosenObjects )
{
string config = _configurationDAO.GetConfigurationById(item.configId);
ObjectViewModel .SubObjectViewModel SubObject = new ObjectViewModel .SubObjectViewModel { IdObject = item.Id, Name = item.Name , Config = config };
listSubObject.Add(setorVM);
}
ObjectViewModel objVM = ObjectViewModel{
name ="test",
value = 2,
IsCameraPermited =true,
listSub = listSubObject,
choosenSubObjects = listSubObject
};
return View(objVM);
}
My View
#model Project.Models.ViewModels.ObjectViewModel
... more code
<form asp-action="Create">
<div class="row">
<div class="col-sm-6 ctnFullHeight">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ctnFullHeight">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input asp-for="name " class="form-control" />
<span asp-validation-for="name " class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="IsCameraPermited" class="control-label"></label>
<input asp-for="IsCameraPermited" type="checkbox" />
</div>
<div class="form-group float-right position-relative">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
<div class="col-sm-6">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ">
#foreach (var item in listSub)
{
<div class="txt">
#item
</div>
}
</div>
</div>
</div>
</form>
Thanks in advance.
how should I return the ViewModel 'ObjectViewModel' to the controller with all its values
To achieve above requirement, you can refer to the following code snippet.
#model ObjectViewModel
#{
ViewData["Title"] = "Create";
var choosenSubObjects = Model.choosenSubObjects;
}
<form method="post">
<div class="row">
<div class="col-sm-6 ctnFullHeight">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ctnFullHeight">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input asp-for="name " class="form-control" />
<span asp-validation-for="name " class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="IsCameraPermited" class="control-label"></label>
<input asp-for="IsCameraPermited" type="checkbox" />
</div>
<div class="form-group float-right position-relative">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
<div class="col-sm-6">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ">
#for (var i = 0; i < Model.choosenSubObjects.Count; i++)
{
<div class="txt">
<div class="form-group">
<label asp-for="#choosenSubObjects[i].IdObject" class="control-label"></label>
<input asp-for="#choosenSubObjects[i].IdObject" type="text" />
</div>
<div class="form-group">
<label asp-for="#choosenSubObjects[i].Name" class="control-label"></label>
<input asp-for="#choosenSubObjects[i].Name" type="text" />
</div>
<div class="form-group">
<label asp-for="#choosenSubObjects[i].Config" class="control-label"></label>
<input asp-for="#choosenSubObjects[i].Config" type="text" />
</div>
</div>
}
</div>
</div>
</div>
</form>
Controller Actions
[HttpGet]
public IActionResult Create(int id)
{
//code logic here
//...
return View(objVM);
}
[HttpPost]
public IActionResult Create(ObjectViewModel objectViewModel)
{
//code logic here
//...
Test Result
How can I save into my db this the selected option, Right now It's saving all the data but the ProfileText that is what I need...
I think I need to add an asp-for but I dont know where to be honest, or if it's a different way please tell me.
Here is my view:
#model HCCBPOHR.Data.Candidate
#*#model HCCBPOHR.DomainModel.CandidateModel*#
#*#model HCCBPOHR.Services.CandidateService.PostBoth*#
#{
ViewData["Title"] = "CandidateCreate";
}
<h2>CandidateCreate</h2>
<h4>Candidate</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post" enctype="multipart/form-data" asp-action="CandidateCreate">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Number" class="control-label"></label>
<input asp-for="Number" class="form-control" maxlength="9" />
<span asp-validation-for="Number" class="text-danger"></span>
</div>
<div class="form-group">
#Html.DropDownList("ProfileText", "Select Profile")
</div>
<div class="form-group">
<label asp-for="CV" type="file" class="control-label"></label>
<input asp-for="CV" type="file" class="form-control" />
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" onclick="this.disabled=true;this.form.submit();" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
Here is my Model:
public class Candidate : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public int Number { get; set; }
public string ProfileText { get; set; }
public Byte[] CV { get; set; }
public string CVNAME { get; set; }
public List<Profile> ProfileList { get; set; }
}
This is how I'm sending the List to the View:
public IActionResult CandidateCreate(int postId)
{
using (var applicationcontext = new ApplicationContext())
{
IEnumerable<SelectListItem> items = applicationcontext.Profile.Select(c => new SelectListItem{Value = c.ProfileText,Text = c.ProfileText});
ViewBag.ProfileText = items.ToList();
return View();
}
}
The error that I'm having right now is
NullReferenceException: Object reference not set to an instance of an object.
In your view change the code to:
<div class="form-group">
<select asp-for="ProfileText" asp-items="#Model.ProfileList"></select>
</div>
Then in your model you'll have a property which we can call ProfileText which will then get post to the server when the form is submitted.
Change your model by introducing a new prop as follows:
public SelectList ProfileList { get; set; }
Now in your action your will need to do:
var model = new Candidate();
...
model.ProfileList = new SelectList(YourProfileListFromDbOrSomeWhereElse);
return View(model);
Please note you can also use SelectList(IEnumerable, string dataValueField, string dataTextField)Constructor if you want to set the dataValueField and dataTextField. I do not know how you get your ProfileList and what it contains so hence why I've only made use of the SelectList(IEnumerable items); Constructor.
Further reading here
As I can see, you are not populating the dropdownlist. I think it's better practice to have the values that can be selected(in a SelectList or string list) and a variable that will hold the selected value in your model and use DropDownListFor. the syntax would be:
#Html.DropDownListFor(model => model.ProfileText, new SelectList(Model.ProfileList, "name"), new {(here html attributes)#class = "form-control"})
After doing that you will get the selected value when posting the model