How to create a good custom DropDownList / ComboBox item in Blazor? - combobox

I want to use multiple ComboBox-Styled-Items on my Blazor-Server-App. My working code for this looks like this:
#page "/dropdownlist"
<h3>DropDownList - ComboBox</h3>
<select class="form-control col-6" #onchange="#(x => OnSelChange(x.Value.ToString()))">
<option value="">--SelectName--</option>
#foreach (var test in TestModelsLst)
{
<option value=#test.Id>#test.Name</option>
}
</select>
#if (SelectedTestModel != null)
{
<p>Sel TestModel-Obj.Name: #SelectedTestModel.Name</p>
}
#code {
public TestModel SelectedTestModel;
public void OnSelChange(string guidAsString)
{
SelectedTestModel = TestModelsLst.FirstOrDefault(x => x.Id.ToString() == guidAsString);
}
//---------------
public List<TestModel> TestModelsLst = new List<TestModel>
{
new TestModel("Jonny"),
new TestModel("Sarah"),
new TestModel("Tom")
};
public class TestModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public TestModel(string name)
{
Id = Guid.NewGuid();
Name = name;
}
}
}
Questions:
1.
Is there a way to pass the Class-Obj. instead of passing Guid->string->SearchinLst -> select Obj.
e.g.: <option value=#test> #test.Name </option> (without the valueStuff)
2.
If my code is okay. The one thing that bothers me, is that I can't figur out to use a placeholder="--SelectName--" as I did in EditForms. In my solution right now user can select the option --SelectName--.
Thx

Is there a way to pass the Class-Obj. instead of passing Guid->string->SearchinLst -> select Obj. e.g.:
#test.Name (without the valueStuff)
Nope. The value property of the option element cannot be an object.
If my code is okay. The one thing that bothers me, is that I can't figur out to use a placeholder="--SelectName--" as I did in EditForms.
In my solution right now user can select the option --SelectName--.
If I understand correctly, the following might solve it (see attributes of --SelectName-- option) ...
<select class="form-control col-6" #onchange="#(x => OnSelChange(x.Value.ToString()))">
<option value="" disabled selected hidden>--SelectName--</option>
#foreach (var test in TestModelsLst)
{
<option value=#test.Id>#test.Name</option>
}
</select>

Related

Setting a value in Controller from Visualforce Page is taking too long

I'm using Visualforce Page to display some selection fields, and based on the selections I'm updating my list.
<apex:form>
<div class="map-controls">
<div class="map-selects">
<apex:selectList value="{!state}" multiselect="false" size="1">
<apex:selectOptions value="{!states}"></apex:selectOptions>
<apex:actionSupport event="onchange" rerender="countyList" />
</apex:selectList>
<apex:selectList value="{!county}" multiselect="false" size="1" id="countyList">
<apex:selectOptions value="{!counties}"></apex:selectOptions>
</apex:selectList>
</div>
<div class="map-search">
<apex:commandButton value="Search" action="{!test}" rerender="productlistpanel" status="status" />
</div>
<div class="radio-btns">
<apex:selectRadio value="{!type}">
<apex:selectOptions value="{!types}" />
</apex:selectRadio>
</div>
</div>
</apex:form>
Basically what I'm trying to do here is, when user selects the State, County and Type upon clicking the commandButton, the product list will be rendered.
<apex:outputPanel id="productlistpanel">
<div class="splide" role="group">
<div class="splide__track">
<ul class="splide__list">
<apex:repeat value="{!products}" var="productKey" id="theRepeat">
<!-- REPEAT CONTENT -->
</apex:repeat>
</ul>
</div>
</div>
<script>
document.dispatchEvent(new CustomEvent("splideTest", { "detail": 'TEST' }));
</script>
</apex:outputPanel>
And this is my controller.
public List<SelectOption> getTypes() {
RecordTypeInfo TYPE1 = Schema.SObjectType.Product2.getRecordTypeInfosByDeveloperName().get('TYPE1');
RecordTypeInfo TYPE2 = Schema.SObjectType.Product2.getRecordTypeInfosByDeveloperName().get('TYPE2');
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption(TYPE1.getRecordTypeId(), 'TYPE1'));
options.add(new SelectOption(TYPE2.getRecordTypeId(), 'TYPE2'));
return options;
}
public List<SelectOption> getStates() {
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption('All', 'All'));
List<State__c> states = [SELECT Id,
Name
FROM State__c];
for (State__c s : states) {
options.add(new SelectOption(s.Name, s.Name));
}
return options;
}
public List<SelectOption> getCounties() {
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption('All', 'All'));
List<County__c> counties = new List<County__c>();
if (state != null && state != 'ALL') {
counties = [SELECT Id,
State__c,
Name
FROM County__c
WHERE State__r.Name = :state];
}
for (County__c c : counties) {
options.add(new SelectOption(c.Name, c.Name));
}
return options;
}
public PageReference test() {
return null;
}
public String state { get; set; }
public String county { get; set; }
public String type { get; set; }
public Map<Id, WRAPPER> productList { get; set; }
public Map<Id, WRAPPER> getProducts() {
try {
// CREATE QUERY
query += String.isNotBlank(state) && state != 'ALL' ? ' AND State__c = \'' + state + '\'' : '';
query += String.isNotBlank(county) && county != 'ALL' ? ' AND County__c = \'' + county + '\'' : '';
query += String.isNotBlank(type) ? ' AND RecordTypeId = \'' + type + '\'' : '';
query += ' ORDER BY Name ASC';
System.debug('query ' + query);
List<Product2> productList = (List<Product2>)database.query(query);
for (Product2 prod : productList) {
// CREATE LIST
}
return returnMap;
} catch (Exception ex) {
ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.Error, ex.getMessage());
ApexPages.addMessage(msg);
return null;
}
}
My problem is when I select the type and hit Search; the type is not available right away. I can see the rerender is being executed and at the logs I see that type is not saved. I have to click Search button again to see the Type selected as I wanted it to be.
I usually use Lightning Web Component and I don't deal with this kind of problem but unfortunately, I have to use VF Page for this implementation.
I could not locate any work-around so far, I tried to understand the delay, but it seems like it is not a common issue. I assume it is a design issue on my end. I couldn't locate why setting the value is not fast enough.
Does that happen to you, or do you have any suggestions for it?
You could cheat, write it in LWC and then use "Lightning Out" to display it. Saves the hassle of eventually rewriting it ;)
I suspect part of it is that only 1st picklist has apex:actionSupport.
You swallow the exception (maybe there's an issue with the query) and use addMessage - but for it to truly show you need <apex:pageMessages id="messages" /> tag and then add it to your rerender (rerender="productlistpanel,messages")
Your "type" picklist radio is the only one without fallback "ALL". I suspect in UI it apppears to have type1 selected as 1st entry but really the value is null because you didn't initalise it in controller? See if it behaves better if you explicitly set it in constructor for example.
Risko of soql injection (could use bind variables, even in dynamic soql), you could read about <apex:actionRegion> for such partial form submits. Shameless plug: https://salesforce.stackexchange.com/a/22216/799

How to return an array to its first value? Angular

I need your help. In my Angular application, I accept an array and try to filter it by a certain field. The point is that I have the normal filtering working, however, I need to return the array to the very first value: as if the page had just loaded. I tried to do this with the spread operator, but when I click on it, I have no element on the page. Please tell me how to implement this? Thank you very much
HTML
<div>
<select
formControlName="category"
(change)="filterProductsCategorySelectOption()">
<option [value]="firstDataValue">Reset</option>
<option
*ngFor="let category of allProductsCategories"
[value]="category"
> {{category}} </option>
</select>
</div>
<div *ngFor="let product of filteredProductList" class="different"></div>
TypeScript
public allProductsCategories: string[] = ["electronics", "jewelery", "men's clothing", "women's clothing"]
public allProductList: any;
public filteredProductList: any;
public firstDataValue: any;
ngOnInit(): void {
this.form = new FormGroup({
category: new FormControl(null),
})
this.productService.getAllProducts().subscribe(value => {
this.allProductList = this.filteredProductList = value;
})
this.firstDataValue = [...filteredProductList];
}
public filterProductsCategorySelectOption(): void {
const categoryOptionValue = this.form.controls['category'].value;
this.filteredProductList = this.allProductList.filter(el => el.category === categoryOptionValue);
}
I've filled out your example to create a working Stackblitz.
HTML:
<div [formGroup]="form">
<select formControlName="category">
<option value="reset">Reset</option>
<option *ngFor="let category of allProductsCategories" [value]="category">
{{ category }}
</option>
</select>
</div>
<div *ngFor="let product of filteredProductList" class="different">
{{ product.name }}
</div>
TS:
public allProductsCategories: string[] = [
'electronics',
'jewelery',
"men's clothing",
"women's clothing",
];
public allProductList: any;
public filteredProductList: any;
public form;
constructor(private productService: ProductService) {}
ngOnInit(): void {
this.form = new FormGroup({
category: new FormControl(null),
});
this.productService.getAllProducts().subscribe((value) => {
this.allProductList = value;
this.filteredProductList = [...this.allProductList];
});
this.form.controls['category'].valueChanges.subscribe((val) => {
if (val === 'reset') {
this.filteredProductList = [...this.allProductList];
return;
}
this.filteredProductList = this.allProductList.filter(
(el) => el.category === val
);
});
}
You don't need firstDataValue because you've already cached all products in allProductList. You do need to make a copy of the allProductList as filteredProductList or else you will be changing the value of both when you reassign filteredProductList to the filtered list of products.
Also, instead of binding to the native change event, it makes more sense to subscribe to the value changes of your input since you're using Reactive Forms.
🚀 StackBlitz Here 🚀

binding two selects angular

I have two selects
The first one is for regions
and the second one for cities
The first one is filled with regions
Now i have a methode that brings cities by the id of the region .
I dont know how to get the idregion and put it into the params function
This is my first select
<div class="form-group">
<label for="">Region</label>
<select class="form-control"
[(ngModel)]="region" name="Region">
<option></option>
<option *ngFor="let region of
objectKeys(dropDownList2)|keys"
[value]="dropDownList2[region].idRegion">
{{dropDownList2[region].nomRegion}}
</option>
</select>
</div>
My services :
getville() {
return this.http.get(this.urltest + 'Villes');
}
getRegion() {
return this.http.get(this.urltest + 'Regions');
}
GetRegionVille(idRegion) {
return this.http.get(this.urltest + 'Villes/GetRegionVille/' + idRegion);
}
My component.ts :
getidregion() {
this.res.getRegion().subscribe(R => {
this.dropDownList2 = R as any;
});
}
getregionville() {
this.res.GetRegionVille(****i don t know how to get the idregion**** )
.subscribe(response => {
this.dropDownList = response as any;
});
}
this is my function
// GET: api/Villes
[HttpGet("GetRegionVille/{id}")]
public async Task<IActionResult> GetRegionVille([FromRoute] int id)
{
var req = from v in _context.Villes
join r in _context.Regions
on v.IdRegion equals r.IdRegion
where r.IdRegion == id
select new {v.NomVille };
return Ok(req);
}
My select of the cities :
<div class="form-group">
<label for="">Ville</label>
<select class="form-control" name="Ville"
[(ngModel)]="ville">
<option></option>
<option *ngFor="let ville of objectKeys(dropDownList) |
keys"
[value]="dropDownList[ville].idVille">
{{dropDownList[ville].nomVille}}
</option>
</select>
The selected value will be in region variable as you state [(ngModel)]="region" and you can use (ngModelChange)="onChange($event)" to get an event when value changes
I am not sure if using two way data binding with (ngModelChange) is efficient, so please see this answer How can I get new selection in "select" in Angular 2?

angularjs bootstrap typeahead return child

My input binds to object line.product however typeahead is returning the list of pairs of products and supplier. The current ps.product as ps.product.code for ps in getProductSupplierRefList($viewValue) does not return the expected product.
<input ng-model="line.product"
class=" form-control"
typeahead="ps.product as ps.product.code for ps in getProductSupplierRefList($viewValue)"
typeahead-loading="isLoading"
typeahead-on-select="productSupplierSelected($item, line)"
typeahead-template-url="productSupplierRefList.html"/>
getProductSupplierRefList calls webapi and return a list of ProductSupplierRefModel:
public class ProductSupplierRefModel
{
public ProductRefModel Product { get; set; }
public SupplierRefModel Supplier { get; set; }
}
The product code is expected in text control:
Any suggestion pls?
use typeahead-input-formatter to show the code. looks like ps.product as ps.product.code is not working???
<input ng-model="line.product"
type="text"
class=" form-control"
ng-keyup="getProductSupplierRefList($event)"
typeahead="ps.product as ps.product.code for ps in filterProductSuppliers"
typeahead-loading="isLoading"
typeahead-input-formatter="formatProduct($model)"
typeahead-wait-ms=500
typeahead-on-select="productSupplierSelected($item, line)"
typeahead-template-url="productSupplierRefList.html" />
where the formatter is:
$scope.formatProduct=function(model) {
return model ? model.code : '';
}
the product code now appears as expected:
Don't use function in typehead. Also be careful about the model properties camel case.
<input ng-model="line.product"
class=" form-control"
ng-keyup="getProductSupplierRefList($event)"
typeahead="ps.Product as ps.Product.Code for ps in productOptions"
typeahead-loading="isLoading"
typeahead-on-select="productSupplierSelected($item, line)"
typeahead-template-url="productSupplierRefList.html"/>
$scope.productOptions = [];
$scope.getProductSupplierRefList = function(evt){
var value = angular.element(evt.target).val();
$http.get('url/' + value).then(funtion(response){
$scope.productOptions = response.data;
})
}
//test ps.Product.Code with _tojson(ps.Product.Code)
$scope._tojson= function(obj){
return angular.toJson(obj);
}

Angular ng-options mapping "select" portion to different model properties

I'm trying to use ng-options to select a Role.
I have Role objects that look like this:
{
Id: 'someRoleId',
Name: 'someRoleName
}
and then a list of select options that come from the server like this:
{
Value: 'someRoleId'
Text: 'someRoleName',
}
Currently I have this select field bound to the Role property of party on the controller.
<select ng-model="party.Role" ng-options="o as o.Text for o in options.RoleOptions track by o.Value" />
It correctly translates the options, but the selected value (o) doesn't have matching properties, so the binding doesn't work. Is there any way to map the Value to Id, and Text to Name using ng-options?
Thanks!
Try this..
Markup:
<select ng-model="role" ng-options="o as o.Text for o in options.RoleOptions track by o.Value" ng-model-options="{getterSetter:true}"/>
Controller:
var _role;
$scope.role = function (val) {
if (angular.isDefined(val)) { //setter
_role = {
'Id': val.Value,
'Name': val.Text
}
} else {
//getter
return {
'Value': _role.Id,
'Text': _role.Name
};
}
}

Resources