Trouble with Request.Form inside .cshtml - asp.net-core

Trying to create a page that will have a drop down selector with three image names and when an image name is selected and you hit submit it will then display that image on the page.
I found an example of this here(Seems to be outdated): https://learn.microsoft.com/en-us/aspnet/web-pages/overview/ui-layouts-and-themes/9-working-with-images
has: if(Request["photoChoice"] != null)
Read somewhere that the correction is Request.Form
#{ var imagePath = "";
if (Request.Form["photoChoice"] != null)
{
imagePath = #"images\" + Request.Form["photoChoice"];
}
}
<form method="post" action="">
<div>
I want to see:
<select name="photoChoice">
<option value="Photo1.jpg">Photo 1</option>
<option value="Photo2.jpg">Photo 2</option>
<option value="Photo3.jpg">Photo 3</option>
</select>
<input type="submit" value="Submit" />
</div>
<div style="padding:10px;">
#if (imagePath != "")
{
<img src="#imagePath" alt="Sample Image" width="300" />
}
</div>
</form>
The first error I was having was:
" Operator '!=' is ambiguous on operands of type 'StringValues' and 'null' "
adding (object) at the start of the Request there in the if statement
#{ var imagePath = "";
if ((object)Request.Form["photoChoice"] != null)
{
imagePath = #"images\" + Request.Form["photoChoice"];
}
Now I am getting another error "InvalidOperationException: Incorrect Content-Type" when I try to compile the site. It does refer to the If line of code

The link you refer to is used in asp.net, not in core.
The main reason for the error is that you put the request.Form in the
wrong place. Your current requirements should put the code
into the OnPost method in the code behind.
There are many ways to implement this function in the core, but they need to be triggered in the post method in the code behind.
Please refer to this.
The simplest way is to bind fields in the code behind. Please refer to the following for details.
Page.cs:
public class ShowImagesModel : PageModel
{
[BindProperty]
public string imagePath { get; set; }
[BindProperty]
public string photoChoice { get; set; }
public void OnGet()
{
imagePath = "";
}
public void OnPost()
{
if (!string.IsNullOrEmpty(photoChoice))
{
imagePath = #"images\" + photoChoice;
}
}
}
View:
#page
#model WebApplication1_razor_page.ShowImagesModel
#{
ViewData["Title"] = "ShowImages";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<h1>ShowImages</h1>
<form method="post" action="">
<div>
I want to see:
<select asp-for="photoChoice" >
<option value="Photo1.jpg">Photo 1</option>
<option value="Photo2.jpg">Photo 2</option>
<option value="Photo3.jpg">Photo 3</option>
</select>
<input type="submit" value="Submit" />
</div>
<div style="padding:10px;">
#if (Model.imagePath != "")
{
<img src="#Model.imagePath" alt="Sample Image" width="300" />
}
</div>
</form>
Here is the result:

Related

model property is not passed to controller action

What is my mistake? AllFindedBrands property is not passing to SearchBrandResult Action of Controller
Controller:
public async Task<IActionResult> Search(string Articul, int idClient)
{
List<BrandList> findedBrands = new List<BrandList>();
#ViewBag.list = woDupes;
SearchViewModel model = new SearchViewModel();
model.Articul = Articul;
model.idClient = idClient;
model.AllFindedBrands = new List<BrandList>(findedBrands);
return View(model);
}
[HttpPost]
public async Task<IActionResult> SearchBrandResult(SearchViewModel model)
{
return View();
}
View:
<form asp-controller="Search" asp-action="SearchBrandResult" asp-route-
Articul="#Model.Articul"
asp-route-AllFindedBrands="#Model.AllFindedBrands" asp-route-
idClient="#Model.idClient" method="post" enctype="multipart/form-data">
<select asp-for="SelectedBrand" asp-items="#(new SelectList(#ViewBag.list,
nameof(FindedBrand.Name),
nameof(FindedBrand.Name)))"
multiple="true" class="form-control brand-chosen">
</select>
<input type="submit" />
All other properties of ViewModel is successfully passed to th Action
AllFindedBrands is type of complex model and asp-route-* cannot dynamic bind the value. You can F12 in the browser to check the generated url in the form.
Two ways you can follow:
1.By using asp-all-route-data and foreach the AllFindedBrands to bind the value which passes the value by route data.
Assume your model like below:
public class SearchViewModel
{
public string Articul { get; set; }
public string idClient { get; set; }
public List<BrandList> AllFindedBrands { get; set; }
public List<string> SelectedBrand { get; set; }
}
public class BrandList
{
public string Name { get; set; }
}
View(For easy testing, I just hard-coded the dropdownlist):
#model SearchViewModel
#{
var data = new Dictionary<string, string>();
for(int i=0;i<Model.AllFindedBrands.Count();i++)
{
data.Add("AllFindedBrands[" + i + "].Name", Model.AllFindedBrands[i].Name);
}
}
<form asp-action="SearchBrandResult" asp-route-Articul="#Model.Articul" asp-all-route-data="#data" asp-route-idClient="#Model.idClient" method="post" enctype="multipart/form-data">
<select asp-for="SelectedBrand" multiple="true" class="form-control brand-chosen">
<option value="aaa">aaa</option>
<option value="bbb">bbb</option>
<option value="ccc">ccc</option>
</select>
<input type="submit" />
</form>
2.By listing the property and make them hidden inputs which passes the value by form data:
#model SearchViewModel
<form asp-action="SearchBrandResult" asp-route-Articul="#Model.Articul" asp-route-idClient="#Model.idClient" method="post" enctype="multipart/form-data">
#for (int i = 0; i < Model.AllFindedBrands.Count(); i++)
{
<input asp-for="#Model.AllFindedBrands[i].Name" hidden />
}
<select asp-for="SelectedBrand" multiple="true" class="form-control brand-chosen">
<option value="aaa">aaa</option>
<option value="bbb">bbb</option>
<option value="ccc">ccc</option>
</select>
<input type="submit" />
</form>

blazorstrap InputType.select not binding

trying to create a very basic form with blazorstrap.
#page "/testform"
<h1> test form #Status</h1>
<EditForm Model=#Person OnSubmit=#FormSubmitted>
<DataAnnotationsValidator />
<ValidationSummary />
<p>
<label>
name:
<BSBasicInput T="string"
InputType="InputType.Text"
#bind-value=Person.Name />
</label>
</p>
<p>
<label>
Age:
<InputNumber #bind-Value="Person.Age" />
</label>
</p>
<p>
<label>
type:
<InputSelect #bind-Value="Person.Type">
<option value="">Select classification ...</option>
#foreach (var enumType in Enum.GetValues(typeof(BankAccountType)))
{
<option value="#enumType">#enumType</option>
}
</InputSelect>
#* <BSBasicInput T="BankAccountType?" InputType="InputType.Select" #bind-Value="Person.Type"> *#
#* <option value="">Select classification ...</option> *#
#* #foreach (var enumType in Enum.GetValues(typeof(BankAccountType))) *#
#* { *#
#* <option value="#enumType">#enumType</option> *#
#* } *#
#* </BSBasicInput> *#
</label>
</p>
<input type="submit" value="Submit" class="btn btn-primary" />
</EditForm>
#code
{
string Status = "Not submitted";
Person Person = new Person();
BankAccountType? AccountType = null;
void FormSubmitted()
{
Status = "Form submitted";
Console.WriteLine($"person: {Person} + " + AccountType);
}
private void SelectedChanged(BankAccountType? value)
{
Console.WriteLine("changed " + value);
}
}
the person class is
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public BankAccountType? Type { get; set; }
public override string ToString()
{
var accountType = Type.HasValue ? Type.Value.ToString() : "";
return $"{Name} is {Age} years old {accountType}";
}
}
The name binding with BSBasicInput works fine. using InputSelect for the select works fine. but when I try and use BSBasicInput with the InputType.Select (see commented out part). I cannot get it to bind, or at least show it is ever changing or setting either Person.Type or when I directly create a property in the razor file for it.
Sure I must be doing something wrong here, and its not blazorstrap, but can't see what it is now
<BSBasicInput T="BankAccountType" InputType="InputType.Select" #bind-Value="Person.Type">
<option value="">Select classification ...</option>
#foreach (var enumType in Enum.GetValues(typeof(BankAccountType)))
{
<option value="#enumType">#enumType</option>
}
</BSBasicInput>
This works. It seems to be that BSBasicInput cannot handle nullable enums

Jetstream User Profile Update: problems passing $input[] field using Livewire form input

I added some custom fields to the User Model and it stores them perfectly during registration (country_id, city_id, and state_id), but I am having problems with the profile management/update:
The fields seem to update only when using the jetstream components as input but NOT when I use my dropdown select option input
<x-jet-input id="cap" type="text" class="mt-1 block w-full" wire:model.defer="state.cap" />
So for instance this would update the $input['cap'] key but the "country_id" field from my livewire script does not update the $input['country_id'] ...
<select wire:model="selectedCountry" id="country_id" name="country_id">
<option value="{{$user->country_id}}"> {{$user->country->name}} </option>
#foreach($countries as $country)
<option value="{{$country->id}}"> {{$country->name}} </option>
#endforeach
</select>
<x-jet-input-error for="country_id" class="mt-2" />
To display or hide fields for instance I update the variables such as $SelectedCountry
The Country/City/State fields are displayed using a livewire script that hides or shows a given select dropdown and runs queries only when needed (if a Country has states/regions, it shows them otherwise it shows only the cities from the selected country etc).
If I submit though, the $input['country_id'] key is not changing though and it just keeps the previous value with which I registered.
I assume the jetstream component would do using wire:model.defer="state.country_id" for instance but again I can not use it because is just a text input... any ideas? 😬
Update-Profile-information-Form
...
<div class="col-span-6 sm:col-span-4">
<x-jet-label for="cap" value="{{ __('Postal Code') }}" />
<x-jet-input id="cap" type="text" class="mt-1 block w-full" wire:model.defer="state.cap" />
<x-jet-input-error for="cap" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<x-jet-label for="address" value="{{ __('Address') }}" />
<x-jet-input id="address" type="text" class="mt-1 block w-full" wire:model.defer="state.address" />
<x-jet-input-error for="address" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
#livewire('edit-address', ['user' => Auth::user()])
</div>
...
edit-address.blade.php (view)
<div>
...
<x-jet-label for="country_id" value="{{ __('Country') }}" />
<select wire:model="selectedCountry" id="country_id" name="country_id">
<option value="{{$user->country_id}}"> {{$user->country->name}} </option>
#foreach($countries as $country)
<option value="{{$country->id}}"> {{$country->name}} </option>
#endforeach
</select>
<x-jet-input-error for="country_id" class="mt-2" />
</div>
...
EditAdress.php (livewire script)
class EditAddress extends Component
{
public $countries;
public $states;
public $cities;
public $selectedCountry = null;
public $selectedState = null;
public $selectedCity = null;
public $test = null;
public $user = null;
public function mount(User $user, $selectedCity = null){
$this->countries = Country::all();
$this->states = collect();
$this->cities = collect();
$this->selectedCity = $selectedCity;
if (!is_null($selectedCity)) {
$city = City::with('state.country')->find($selectedCity);
if ($city) {
/*if ($this->states->isEmpty()===1){
$this->cities = City::where('country_id', $this->selectedCountry);
}*/
$this->cities = City::where('state_id', $city->state_id)->get();
$this->states = State::where('country_id', $city->state->country_id)->get();
$this->selectedCountry = $city->state->country_id;
$this->selectedState = $city->state_id;
}
}
}
public function render()
{
return view('livewire.edit-address');
}
public function updatedSelectedCountry($country)
{
;
$this->states = State::where('country_id', $country)->get();
$this->selectedState = NULL;
if(!$this->states->count()){
$this->cities = City::where('country_id', $country)->get();
}
}
public function updatedSelectedState($state)
{
if (!is_null($state)) {
$this->cities = City::where('state_id', $state)->get();
}
else{
$this->cities = City::where('country_id', $this->selectedCountry);
}
}
}

using select options to get value in asp.net razor page

I want to create a select option to input one of a few fixed values and have it return a matching value to a variable similar to how the input text fields, how would I do this? This was my attempt, the <input type="text"> works fine but the select types return null.
<div class="text-center">
<h1 class="display-4">Add new patient</h1>
<form method="post">
<input type="text" asp-for="patientModel.PatientID" placeholder="Patient ID" />
<input type="text" asp-for="patientModel.FirstName" placeholder="First Name" />
<input type="text" asp-for="patientModel.SecondName" placeholder="Second Name" />
<input type="text" asp-for="patientModel.Location" placeholder="Location" />
<select id="active" name="active" asp-for="patientModel.Sex">
<option value="ACTIVE">MALE</option>
<option value="INACTIVE">FEMALE</option>
<option value="OTHER">OTHER</option>
</select>
<select id="active" name="active" asp-for="patientModel.Active">
<option value="ACTIVE">ACTIVE</option>
<option value="INACTIVE">INACTIVE</option>
</select>
<button type="submit">Submit</button>
</form>
</div>
public class addnewpatientModel : PageModel
{
[BindProperty]
public PatientModel patientModel { get; set; }
public void OnGet()
{
}
public IActionResult OnPost()
{
return RedirectToPage("/index");
}
}
Change the name attribute for the select tag or just remove it:
<select id="sex" name="patientModel.Sex" asp-for="patientModel.Sex">
<select id="active" name="patientModel.Active" asp-for="patientModel.Active">
Try this link. I think you'll find an answer here
The select element has a name attribute. This is used as the key for any selected value(s) when a form is submitted. You can access the value by passing the key as an indexer to the Request.
var value = Request.Form["active"];
The recommended approach, however is to add a suitable property to the PageModel and to allow model binding to apply the posted value to the property:
public class addnewpatientModel : PageModel
{
[BindProperty]
public int active { get; set; }
public void OnPost()
{
// posted value is assigned to the Number property automatically
}
}

choosing between 2 actions in one controller with single view by checkbox

I got 2 actions in my controller, I want to choose which action to execute by checkbox in my razor view.
here is my controller:
public ActionResult Person(string searchString)
{
var person = from p in db.Persons
select p;
if (!String.IsNullOrEmpty(searchString))
{
person = person.Where(oo => oo.Name.ToUpper() == searchString);
}
return View(person);
}
public ActionResult Job(string jobString)
{
var jobs = from j in db.Jobs
select j;
if (!String.IsNullOrEmpty(jobString))
{
jobs = jobs.Where(oo => oo.Name.ToUpper() == jobString);
}
return View(jobs);
}
when I check a case I would like to execute the query search for this specific case
here is my view:
<div>
<form method="POST">
<div>
<input type="checkbox" name="Person" value="Person" style="margin-left: 54px"/>Person
</div>
<div class="Job">
<input type="checkbox" name="Job" value="Job" />Job
</div>
#using (Html.BeginForm())
{
<p>
<input type="text" name="SearchString" style="margin-left: 90px;" />
<input type="submit" value="Search" />
</p>
}
</form>
Post to a single action method, then call one of your existing methods depending on the value of the checkbox.
public ActionResult Search(bool isJobSearch, string searchString)
{
if (isJobSearch)
{
return Job(searchString);
}
else
{
return Person(searchString);
}
}
private ActionResult Person(string searchString)
{
// As your example
}
private ActionResult Job(string jobString)
{
// As your example
}
I am just correcting your html
Your html contains two form tags. I am not sure about the usage of form with in form tags. html.beginform will create internally another form tag when gets executed.So better one form tag will contain all elements to make a post.
#using (Html.BeginForm("Search","Home"))
{
<div>
<input type="checkbox" name="Person" value="Person" style="margin-left: 54px"/>Person
</div>
<div class="Job">
<input type="checkbox" name="Job" value="Job" />Job
</div>
<p>
<input type="text" name="SearchString" style="margin-left: 90px;" />
<input type="submit" value="Search" />
</p>
}
}
in controller
public ActionResult Search(FormCollection form)
{
//do some condition based on your needs
if(form["SearchString"]=="Job")
return RedirectToAction("Job");
else
return RedirectToAction("Person");
}
public ActionResult Person()
{
}
public ActionResult Job()
{
}