I need to be able to run a function after a selection in made in a <select>. The issue is I'm also binding with #bind and I get a error when I try to use #onchange stating that it is already in use by the #bind. I tried using #onselectionchange, but that does nothing(doesn't run the function). I could forget the #bind and just assign #onchange to a function, but I'm not sure how to pass the selected value to the function.
I have the following code:
<select #bind="#SelectedCustID" # #onchange="#CustChanged" class="form-control">
#foreach (KeyGuidPair i in CustList)
{
<option value="#i.Value">#i.Text</option>
}
</select>
Thanks.
#bind is essentially equivalent to the having both value and #onchange, e.g.:
<input #bind="CurrentValue" />
Is equivalent to:
<input value="#CurrentValue" #onchange="#((ChangeEventArgs e) => CurrentValue = e.Value.ToString())" />
Since you've already defined #onchange, instead of also adding #bind, just add value to prevent the clash:
<select value="#SelectedCustID" #onchange="#CustChanged" class="form-control">
#foreach (KeyGuidPair i in CustList)
{
<option value="#i.Value">#i.Text</option>
}
</select>
Source: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-3.1
<select #bind="MyProperty">
<option>Your Option<option>
</select>
#code {
private string myVar;
public string MyProperty
{
get { return myVar; }
set
{
myVar = value;
SomeMethod();
}
}
private void SomeMethod()
{
//Do something
}
}
Just add #bind-value and #bind-value:event="oninput" with #onchange as below. Note the lower case letters. This works for me without any issue.
<select #bind-value="variablenametokeepselectedvalue" #onchange="yourmethodname" #bind-value:event="oninput">
<option value="1">Test</option>
</select>
This seems to be a popular confusion. Firstly you cant use #onchange since it would internally be used by #bind. You should be able to access the selected value from the setter of your CustChanged property. Based on what you are trying to do with your CustChanged, you may not even need to manually check when this value is updated. For instance, if your intent is to use CustChanged in your UI directly or indirectly (within Linq or something), the UI would automatically update with CustChanged value when your <select> is changed. Hence, for most use cases I don't see the need to check when it was updated.
To use #onchange, you can bind it to a function something like this:
public void OnUpdated(ChangeEventArgs e)
{
var selected = e.Value;
}
You can avoid #bind altogether (if you're using a foreach):
<select #onchange=#(handleChange)>
#foreach (var option in _options){
<option value=#option.Id selected=#(SelectedId == option.Id)>#option.Name</option>
}
</select>
#code {
public record Person(int Id, string Name);
public int SelectedId { get; set; }
public List<Person> _options = new List<Person>() {
new Person(1,"A"),
new Person(2,"B"),
new Person(3,"C")
};
public void handleChange(ChangeEventArgs args) {
Console.WriteLine(args.Value);
SelectedId = Int32.Parse(args.Value.ToString());
}
}
Some sordid details: I was getting some weird behavior when trying to use F# with server-side Blazor. In short, setting the List of options to the result of an Entity Framework query (mapped to a list of records) wouldn't #bind properly, but using a dummy list of options that were C# classes and not F# records did work. It wasn't due to it being records though, because if I set the list to the EF query and then immediately set it to a dummy list of records, it still didn't #bind properly - but it did work if I commented out the EF line.
Please check this example. It is using #bind but upon setting the value it triggers #onchange event
<div class="form-group">
<label for="client">Client Name</label>
<select id="client" #bind="CheckSelected" class="form-control">
<option value="selected1">selected1</option>
<option value="selected2">selected2</option>
</select>
</div>
#code {
private string selectedItem {get; set;}
private string CheckSelected
{
get
{
return selectedItem;
}
set
{
ChangeEventArgs selectedEventArgs = new ChangeEventArgs();
selectedEventArgs.Value = value;
OnChangeSelected(selectedEventArgs);
}
}
private void OnChangeSelected(ChangeEventArgs e)
{
if (e.Value.ToString() != string.Empty)
{
selectedItem = e.Value.ToString();
}
}
}
Please check below code for reference how we use select tag with bind value and call function onselection value change in blazor
<InputSelect class="form-control mb-0" ValueExpression="#(()=>request.Id)" Value="request.Id"
ValueChanged="#((string value) => SelectedValueChange(value))">
#if (dropdownResponses != null)
{
#foreach (var item in dropdownResponses)
{
<option value="#item.Id.ToString()">#item.Name</option>
}
}
</InputSelect>
use <InputSelect> tag instead of <select> tag and use ValueChanged method for getting call on select value change
here is the code of ValueChanged function
internal void SelectedValueChange(string value)
{
string NewValue = value;
}
Starting from .NET 7 Preview 7, the recommended way to handle this issue is to use the bind:after modifier.
Here is a small example (partially borrowed from the docs):
<p>
<label>
Select one or more cities:
<select #bind="SelectedCities" multiple #bind:after="DoSomething">
<option value="bal">Baltimore</option>
<option value="la">Los Angeles</option>
<option value="pdx">Portland</option>
<option value="sf">San Francisco</option>
<option value="sea">Seattle</option>
</select>
</label>
</p>
<span>
Selected Cities: #string.Join(", ", SelectedCities)
</span>
#code {
public string[] SelectedCities { get; set; } = new[] { "bal", "sea" };
// Run your logic here after a binding event
private void DoSomething()
{
Console.WriteLine(string.Join(',', SelectedCities));
}
}
My recommendation is, if possible, use an EditForm wrapper around your form elements. Then you can detect a change of any of the form elements, in one place. This is good for, for example, a bunch of search filters. Any change in any of the filters should trigger another query of the data, etc.
Example of how to trigger event on form changes is here:
blazor editform change events
According to Microsoft's documentation, this is their preferred way of handling this problem:
<InputText Value="#NewPaymentAmount" class="mdl-textfield__input"
ValueExpression="() => NewPaymentAmount"
ValueChanged="(string value) => ValidateAmount(value)" />
private void ValidateAmount(string amount)
{
NewPaymentAmount = amount;
// Do validation or whatever
}
Or the async way:
<InputText Value="#NewPaymentAmount" class="mdl-textfield__input"
ValueExpression="() => NewPaymentAmount"
ValueChanged="async (string value) => await ValidateAmountAsync(value)" />
private async Task ValidateAmountAsync(string amount)
{
NewPaymentAmount = amount;
// Do validation or whatever
}
<div class="form-group">
<label for="client">Client Name</label>
<select class="form-control" #onchange="#((e) => { myVar = e.Value.ToString(); MyMethod(); })">
<option value="val1">val1</option>
<option value="val2">val2</option>
</select>
</div>
This is how I was able to set the property while calling for a method in the #onchange event.
-Blazor Server
-Dotnet Core 3.1
I use oninput to essentially have bind and onchange.
oninput triggers when the input value is changed whereas bind/onchange triggers when the element loses focus and the input has changed.
This might not fit every scenario however as it wll trigger on every input while typing, depending on your need or for inputs such as selects, radios, etc. it should be suitable.
I was trying the sample example given at [a link]http://docs.adobe.com/docs/en/aem/6-0/develop/sightly/use-api-in-java.html. I have created the component SightlyTest in which the data-sly-call to the template does not work. Below are my files inside component:
extra.html
<template data-sly-template.extra="${# text}"
data-sly-use.extraHelper="${'ExtraHelper' # text=text}">
<p>${extraHelper.reversedText}</p>
</template>
ExtraHelper.java
package apps.AEMProject.components.content.SightlyTest;
import com.adobe.cq.sightly.WCMUse;
public class ExtraHelper extends WCMUse {
private String reversedText;
public String getReversedText() {
return reversedText;
}
#Override
public void activate() throws Exception {
String text = get("text", String.class);
reversedText = new StringBuilder(text).reverse().toString();
System.out.print("reversedText ::: "+reversedText);
}
}
SightlyOp.java
package apps.AEMProject.components.content.SightlyTest;
import com.adobe.cq.sightly.WCMUse;
public class SightlyOp extends WCMUse {
private String lowerCaseTitle;
private String lowerCaseDescription;
#Override
public void activate() throws Exception {
lowerCaseTitle = getProperties().get("title", "").toLowerCase();
lowerCaseDescription = getProperties().get("description", "").toLowerCase();
}
public String getLowerCaseTitle() {
return lowerCaseTitle;
}
public String getLowerCaseDescription() {
return lowerCaseDescription;
}
}
SightlyTest.html
<div data-sly-use.sg="SightlyOp"
data-sly-use.extra="extra.html">
<h1>${sg.lowerCaseTitle}</h1>
<p>${sg.lowerCaseDescription}</p>
<div data-sly-call="${extra # text=properties.description}"></div>
</div>
sg.lowerCaseTitle & sg.lowerCaseDescription is working fine, but nothing display for data-sly-call
Thanks
Try this in SightlyTest.html instead,
<div data-sly-use.sg="SightlyOp" data-sly-use.extra1="extra.html">
<h1>${sg.lowerCaseTitle}</h1>
<p>${sg.lowerCaseDescription}</p>
<div data-sly-call="${extra1.extra # text=properties.description}"></div>
</div>
Modified to data-sly-use.extra1 to differentiate between the variable and the template being called.
I realize I've come to the party a little late, but I'd like to expand on Aditya's answer.
Think of the file extra.html more like a "library" of data-sly-templates rather, since it could contain as many of them as you want (each with a different name). So when you "use" the extra.html file you're sort of importing those templates into a namespace you provide on the use statement. You can then call the templates using that "namespace".
<div data-sly-use.sg="SightlyOp"
data-sly-use.extra="extra.html">
<!--/*${extra} is now a namespace for the templates in extra.html. (you can name it whatever you like for more clarity*/-->
<h1>${sg.lowerCaseTitle}</h1>
<p>${sg.lowerCaseDescription}</p>
<!--/*since your template is called extra, and it's in the namespace called extra you call it with ${extra.extra}*/-->
<div data-sly-call="${extra.extra # text=properties.description}"></div>
</div>
I'm triying to use a conditional #command with an argument passed with Executions.createComponents, this is my java code:
Map data = new HashMap();
data.put("isFromHere", true);
modal = (Window) Executions.createComponents("root/to/window", null, data);
modal.doModal();
And in my zul page I'm trying to do this:
<button label="Save" onClick="#command(arg.isFromHere ? 'save' : 'not')" />
But every time arg.isFromHere is returning false, like the argument is not passed. But if I do this:
<button if="${arg.isFromHere}" label="Save" onClick="#command('save'" />
That does work fine! What means the arguments are getting to the zul page, but not working on conditional commands, Is there a way to make it work?
It has all to do with the lifecycle of the binder.
#Command and ${arg.xxx} are on different lifecycle.
Read this documentation and see your solution in it.
Solution for you :
VM :
private boolean fromHere;
#Init
public void init(#ExecutionArgParam("isFromHere") boolean fromHere){
this.fromHere = fromHere;
}
public boolean isFromHere() {
return fromHere;
}
zul :
<button label="Save" onClick="#command(vm.fromHere ? 'save' : 'not')" />
when I press the insert button, I get the error indicated on the title
Conversion Error setting value '2013-10-26' for 'null Converter'
<h:form id="formulario">
<h:outputLabel for="date">Plazo</h:outputLabel>
<h:inputText id="date" required="true" requiredMessage="Campo Obligatorio" value="#{aaaNewDetalles.criterioAaa.plazo}"/>
<h:message for="date" style="color: red;"/>
<h:commandButton actionListener="#{aaaNewDetalles.add()}" value="Ingresar"/>
</h:form>
the form is managed by this class:
#ManagedBean(name = "aaaNewDetalles")
#ViewScoped
public class aaaNewDetallesBean {
private CriterioAaaController controller;
private CriterioAaa criterioAaa;
#PostConstruct
public void init(){
controller= new CriterioAaaController();
criterioAaa= new CriterioAaa();
}
public void add(){
controller.save(criterioAaa);
}
public CriterioAaa getCriterioAaa() {
return criterioAaa;
}
public void setCriterioAaa(CriterioAaa criterioAaa) {
this.criterioAaa = criterioAaa;
}
}
The object CriterioAaa:
import java.sql.Date;
#Table(name = "criterio_aaa", schema = "", catalog = "ciclos_calidad")
#Entity
public class CriterioAaa extends Entidad implements Serializable {
private Date plazo;
public Date getPlazo() {
return plazo;
}
public void setPlazo(Date plazo) {
this.plazo = plazo;
}
}
There are two problems in your current approach:
You should use java.util.Date instead java.sql.Date. JSF and other frameworks work with this type. Also, java.sql.Date extends java.util.Date but its purpose is basically for JDBC usage. More info about this: Date vs TimeStamp vs calendar?
<h:inputText> expects a String as value, and when sending the data to the managed bean, it also expects the class field is from String type as well. In cases like this, you need to use a converter to tell JSF that this String in fact represents a Date. For this, you may use <f:convertDateTime> tag component.
<h:inputText id="date" required="true" requiredMessage="Campo Obligatorio"
value="#{aaaNewDetalles.criterioAaa.plazo}">
<f:convertDateTime pattern="yyyy-MM-dd" />
</h:inputText>
As a recommendation, you may use a calendar component from third party libraries like PrimeFaces or RichFaces whose provide <p:calendar> and <rich:calendar> component respectively.
You should import the appropriate Date package :
import java.util.Date;
In Managed Bean You should use java.util.Date. and specify the converter.
e.g.
<h:inputText id="date" required="true" requiredMessage="Hire Date"
value="#{empBean.empDetail.hireDate}">
<f:convertDateTime pattern="yyyy-MM-dd" />
</h:inputText>
you can specify the pattern for DateTimeConverter also you can use dateStyle,timeStyle, type.
I'm dynamically adding textboxes to a form on my jsp page using Javascript. When that form is submitted to an action, how does my action get the values of those textboxes? (I'm using Struts 2, btw.) In ASP.NET, I was able to find them in Form.Request/FormCollection. Is there a Struts 2 equivalent? Thanks a million.
In Struts2, you create beans in the form to do submit values. In order to create the input text-box, use the <s> tag. For example :
<s:textfield name="loginBean.userName" label="UserName" required="true" />
Here loginBean is the bean passed to the jsp page when.
Bean consists of variable declarations and getters-setters for the variable.
Then in the back-end Java where the form is submitted to, you can access the same bean.
Declare getter-setter in Java and then you can access the properties of the bean.
public LoginBean getLoginBean() {
return loginBean;
}
public void setLoginBean(LoginBean loginBean) {
this.loginBean = loginBean;
}
public String authenticate() {
String username = loginBean.getUserName();
I would recommend looking at source codes of open-source Struts projects.
It sounds like you're trying to populate a dynamic list. To do that, you just have to use the [n] index syntax at the end of your Action class property name:
HTML:
<input type="text" name="yourCollection[0]" value="first value" />
<input type="text" name="yourCollection[1]" value="second value" />
<input type="text" name="yourCollection[2]" value="third value" />
Action Class:
public class YourAction extends Action {
public List<String> yourCollection;
public List<String> getYourCollection(){
return yourCollection;
}
public void setYourCollection(List<String> aCollection){
this.yourCollection = aCollection;
}
}