I have been working for a while with Blazor Server host model and now i am building forum with it. I have small strange case, maybe someone will help me to find solution.
This is EditForm
<EditForm Model="#Category">
<InputSelect id="category" class="form-select" #bind-Value="#Category.Id">
#foreach (var category in Categories!)
{
<option value="#category.Id">#category.Category</option>
}
</InputSelect>
</EditForm>
This is list of items:
Categories = await _repository!.GetAllCategories();
This is how "GetAllCategories()" looks like:
public async Task<IEnumerable<CategoryEntity>> GetAllCategories()
{
return await _context.Categories.OrderBy(x=>x.Id).ToListAsync();
}
and the thing is:
First item in Select is blank:
How can i make first item as Value of it? Has someone found something similar?
I found solution.
I changed:
<InputSelect id="category" class="form-select" #bind-Value="#Category.Id">
to:
<InputSelect id="category" class="form-select" #bind-Value="#Category.Category">
Related
I can easily bind one value to my model, but what if I want to bind two or more?
Sample code, tried to bind to the complex object but it fails.
Component:
<select id="myClassId" #onchange="SelectionChanged" class="form-control">
<option value=""></option>
#foreach (var myObject in myClassList)
{
<option value="#myObject">#myObject.AccountName</option>
}
</select>
Code
void SelectionChanged(ChangeEventArgs e)
{
Console.WriteLine(((MyClass)e.Value).AccountId);
Console.WriteLine(((MyClass)e.Value).AccountName);
}
UPDATE:
Ended up doing this. Probably not the most elegant solution, but I'm not sure if there are other more "supported" ways.
<select id="myClassId" #onchange="SelectionChanged" class="form-control">
<option value=""></option>
#foreach (var myObject in myClassList)
{
<option value="#myObject.AccountId;#myObject.AccountName">#myObject.AccountName</option>
}
</select>
void SelectionChanged(ChangeEventArgs e)
{
var accountId = e.Value.ToString().Split(";")[0];
var accountName = e.Value.ToString().Split(";")[1];
Console.WriteLine(accountId);
Console.WriteLine(accountName);
}
The value of a select is a string. That is a fundamental limitation of the HTML, and has nothing to do with Blazor. You cannot use an object. Your best bet here is to assign an id or some other uniquely identifying value, and then in your onchange handler, look up the actual object you want to assign using that value.
For SEO purposes I need to render html elements by php. For example I have these elements.
<?php foreach ($elements as $key => $element): ?>
<select name="first" v-model="model[<?= $key; ?>]">
<option value="">Select</option>
<option value="1">Some Text</option>
<option value="2">Some Text</option>
</select>
<select name="second" v-model="model[<?= $key; ?>]>
<option value="">Select</option>
<option value="4">Some Text</option>
<option value="5">Some Text</option>
</select>
...
...
...
<select name="eleven" v-model="model[<?= $key; ?>]>
<option value="">Select</option>
<option value="101">Some Text</option>
<option value="102">Some Text</option>
</select>
<?php endforeach; ?>
And probably I can manipulate these elements like this on vue side.
const count_models = <?= count($elements) ?>; // in the html
const app = new Vue({
el: '#app',
data: {
model:[]
},
mounted(){
console.log(this.model);
for (let $i = 0; $i < count_models; $i++) {
this.model[$i] = "";
}
}
})
I cannot declare the initial values for model[?]. I need an xhr or assign counted items to a javascript variable to get how many select element I have on DOM and to declare initial values as null for each model[]. Even I redeclare the initial values of the models, it doesn't bind. I just put an example on jsFiddle. In Angular1 there was ng-init attribute to declare initial value for the model.
How can I solve this problem ?
https://jsfiddle.net/ks7jmgwv/1/
you just encountered one of the most common gotchas of Vuejs: reactivity (and therefor the lack off)!
The issue here is when the model property is created it's just an empty array/object and any property that you add to that element it's not going to be reactive: that means any kind of change made programmatically won't trigger the Vue's internal whatches, the only reason that the v-model still works is that the changes made by the user and not by the code does actually trigger native HTML events.
You have two possible solutions:
Ignore the reactivy part (but you won't be able to programmatically update the selected value, or at least it won't be visible) and just make sure that the 'Select' option will be selected by default by assigning it the correct value (in that way you can just skip all the default for-loop initialization).
<option :value="undefined" selected="selected" disabled>Select</option>
Follow the offical way suggested by the Vuejs' documentation to add a new property to an object and still having the advantage of reactivity
this.$set(this.model, $i, "");
You can check this plunker in which I'm showing you both the ways of obtaining your goal:
https://jsfiddle.net/8y7eu39z/18/
Also, did you know that for placeholder options in a select you can add the attribute disabled?
Reactivy Reference: https://v2.vuejs.org/v2/guide/reactivity.html
Also: if you want a "null" as a default value but did not manage to find a way to make it being recognized by the "select" options just use :value="null" instead of value="null" and then you should be able to use
this.$set(this.model, $i, null);
I have this collection called servers which is like this: {id, name, code}.
I have this select tag, I iterate over my servers collection and the data() with the model values.
<select v-model="serveur">
<option v-for="server in servers" :key="server.id" :value="server.name">
{{server.name}}
</option>
</select>
.
.
.
data () {
return {
serveur:'',
code:''
}
}
The value "server.name" selected is binded to the model "serveur".
All of this works just fine, but I want the value "server.code to be binded to the model "code"
I can't figure out how to do this. I'm new to vuejs, like I've been working with vue for the first time only two days ago.
This is also my first Stack Overflow "asks" so I hope I am being clear enough.
Thanks in advance.
You really have one independent data item, which I will call selectedServer. It gets the value of the server entry, which contains both name and code.
<select v-model="selectedServer">
<option v-for="server in servers" :key="server.id" :value="server">
{{server.name}}
</option>
</select>
You can simply refer to selectedServer.name and selectedServer.code in the URL you need to assemble from them, or you can create computeds to return those values under whatever names you prefer, like
data: {
selectedServer: {}
},
computed: {
serveur() { return this.selectedServer.name; },
code() { return this.selectedServer.code; }
}
To achieve this, you can bind the select with an array containing 'serveur' and 'code'. But you can't bind the select with multiple variables directly.
You can do comething like that:
<select #input="serveur = $event.name; code = $event.code">
<option v-for="server in servers" :key="server.id" :value="server">
{{ server.name }}
</option>
</select>
If you need fiddle - feel free to ask. It is possible that this example not working :)
I believe you can find an answer here:
https://stackoverflow.com/a/50982485/10954996
that is something I would do - create change handler and change everything I need within handler method
I hope this helps
I want to be able to display a form which changes depending on the value of a select on Dot.Net Core. I've seen many things like dynamic forms, View Components, razor and partials and also there is a lot of info out there but very confusing. Any info about the proper way to do what I want would be very appreciated.
I Have Categories>SubCategories>>Products
An order can be for one Category>>SubCategory only. So I want to display a select and depending on what category the user selects for the new Order, the products that I have to display. So I dont want to pick the user selection and go back to the controller and back to the view again and so on. I want to be able to dynamically display data according to the user selection.
Here an extract of the code just to briefly figure out what Im doing..I am not pasting the classes like Products,etc..
public class OrderCreateViewModel
{
public IEnumerable<Category> Categories { get; set; }
public IEnumerable<Branch> Branches { get; set; }
public int BranchId { get; set; }
public int CategoryId { get; set; }
}
Controller :
[HttpGet]
public IActionResult Create()
{
//Create vm
IEnumerable<Branch> branchList = _branchDataService.GetAll();
IEnumerable<Category> categoryList = _categoryDataService.GetAll();
OrderCreateViewModel vm = new OrderCreateViewModel
{
Categories = categoryList,
Branches = branchList
};
return View(vm);
}
View:
#model OrderCreateViewModel
<p>Create New Order </p>
<form asp-controller="Order" asp-action="Create" method="post">
<div class="form-group">
<label >Select Category</label>
<select class="form-control col-md-2" asp-for="CategoryId"
asp-items="#(new SelectList(Model.Categories ,"CategoryId","Name"))">
</select>
</div>
<div class="form-group">
<label>Select Branch</label>
<select class="form-control col-md-2" asp-for="BranchId"
asp-items="#(new SelectList(Model.Branches,"BranchId","Name"))">
</select>
</div>
<div >
<input type="submit" value="Save" />
</div>
</form>
Im just filling the select on the viewside and depending on what the user picks, the products I want to display. I am not passing the product list yet because I don't know where the "filter" for that particular Category takes place.
Hope you understand the idea of what i need :)
You've got two options here:
# 1 Use a Partial View And AJAX to get your data
Go have a look at the link below, it describes exactly what you want to achieve.
Populating Dropdown using partial view
# 2 Use Javascript to populate your second select:
First off you need to persist your data when the page loads
At the start of your view, add this:
#{
<text>
<script>
var data = "#Newtonsoft.Json.JsonConvert.SerializeObject(Model)";
</script>
</text>
}
Next use your on change event on the branch selector:
At the bottom of your view, do the following in the page ready event:
<script>
(function ()
{
var sltBranch = document.getElementsByName("BranchId")[0];
var sltCat = document.getElementsByName("CategoryId")[0]
sltCat.onchange = function () {
var dataAsObj = JSON.parse(data);
var branches = "";
for (i = 0; i < dataAsObj.Branches.length; i++)
{
if (dataAsObj.Branches[i].CategoryId == sltCat.value)
{
branches += "<option value='" + dataAsObj.Branches[i].BranchId + "'>" + dataAsObj.Branches[i].BranchName + "</option>"; //Whatever The branch name may be
}
}
sltBranch.innerHTML = branches;
}
}
)(document, window);
</script>
I would however advise you to follow option 1 as it is a lot more future proof strategy. This would mean that you need to change your view model etc, but if you plan on making extensive use of this strategy you need to make it more robust with something like option 1.
Good luck anyhow - happy coding.
I'm currently building a website where I have to update two separate targets from a single Ajax.BeginForm. I got it working by using an additional container to container the two separate targets. As in:
Original Form
#model Mod1
#using (Ajax.BeginForm("LoadData", new AjaxOptions{UpdateTargetID = "Div1"}))
{
<select id="sel1" name="sel1" onchange="$(this.form).submit">
// ...
</select>
}
#using (Ajax.BeginForm("ProcessData", new AjaxOptions{UpdateTargetID = "Div2"}))
{
<div id="Div1"></div>
// ...
<input type="submit" value="GO!" />
}
Code File
public ActionResult LoadData(int sel1)
{
// loading data from database
return PartialView(mod1);
}
Partial View
#model Mod2
<select id="sel2" name="sel2">
#foreach (var item in Model.SelectItems)
{
<option value="#item.Value">#item.Text</option>
}
</select>
#foreach (var item in Model.CheckBoxItems)
{
<label>#item.Text<input type="checkbox" id="chk1" name="chk1" value="#item.Value"></label>
}
For the processing method, I have tried:
public ProcessData(Mod1 mod1, string[] chk1, int sel2)
However I am unable to retrieve the values for either chk1 or sel2 upon form submission. examination of chk1 and sel2 in Debug mode, chk1 is null while sel2 is 0 (no such value in the select options). Can anyone please offer some insight into the reason for this and also how I can go about solving it. Thank you in advance.
If I understand you correctly you can do what you want y having two submit buttons on the same form, each calling a separate action method. That way each submit button will have access to all the fields in the form. For a detailed explanation of how you can do that see my answer here:
How to use ajax link instead of submit button for form?
Edit
In response to comment: the action method LoadData should return a partial view that contains the other two controls and have the whole begin form included in it:
#using (Ajax.BeginForm("LoadData", new AjaxOptions{
UpdateTargetID = "Div1",
InsertionMode = InsertionMode.Replace
}))
{
<select id="sel1" name="sel1" onchange="$(this.form).submit">
// ...
</select>
}
<div id="Div1">
</div>
<div id="Div2">
</div>
Move this to another partial view:
#using (Ajax.BeginForm("ProcessData", new AjaxOptions{UpdateTargetID = "Div2"}))
{
// ...
<input type="submit" value="GO!" />
}