I am trying to use MVVM model in zk.
If i use form in zk and try to reset the value it is not binding
<?page title="" contentType="text/html;charset=UTF-8"?>
<zk>
<window border="none" apply="org.zkoss.bind.BindComposer"
viewModel="#id('ix') #init('com.Controller')"
form="#id('fx') #load(ix) #save(ix,before='add')" >
<textbox value="#bind(fx.title)"/>
<button onClick="#command('reverse', fx=fx, field='title')" label="Reverse"/>
</window>
</zk>
#Command
#NotifyChange("title")
public void reverse() {
String value = (String) fx.getField(fieldName);
String newValue = new StringBuilder(value).reverse().toString();
setTitle(newValue);
}
But if i use <textbox value="#bind(ix.title)"/> directly without form it works.
May i know whats wrong with this code.
I'll explain you what's wrong.
<button onClick="#command('reverse', fx=fx, field='title')" label="Reverse"/>
Here you will call the command reverse and you give 2 params with it, fx and field.
#Command
#NotifyChange("title")
public void reverse() {
Here you have your command method but you don't have parameters that you expect.
Its also not needed give the params with it cause Title is propably a global private String.
If you want to give params then this should be the code :
#Command
#NotifyChange("title")
public void reverse(#BindingParam("fx") Form fx, #BindingParam("title") String title) {
second :
form="#id('fx') #load(ix) #save(ix,before='add')" >
Not needed, you use mvvm so you call the vm by ix, this become for you absolete.
The thing what you do here is sometimes needed for grids or lists that the don't update directly by #bind but only by pushing the save button.
This is because #save is so powerfull that it will change the values in the DB without you calling a save method.
#bind(ix.title) is actually the same as #load(ix.title) #save(ix.title) but grouped in one word for sparing code.
Hopes this helps you.
Related
Determine if NgForm Looks Exactly As It Did Before Any User-Input
It seems that form.dirty doesn't redact its value after it has been changed, and form.touched seems to always be false no matter what: dirty is touched, and touched is tetched.
template.html
<form #form="ngForm" (ngSubmit)="handleSubmission($event, {}, form)">
...
<input
#input
type="text"
[name]="item.title"
[(ngModel)]="item.estimate"
(ngModelChange)="handleEstimateChange(item, item.estimate, input, form)"
/>
...
</form>
component.ts
export class LeComponent {
#Input('data') public data: any;
public handleEstimateChange: Function;
constructor(private $: Sandbox) {
this.handleEstimateChange = $.debounce(this.handleEstimate.bind(this), (1000*0.2));
}
handleEstimate(item: any, estimate: number, input: HTMLInputElement, form: NgForm) {
if (!estimate) delete item.esitmate;
(this, item, estimate, input, form);
// Why does form.dirty never change back to pristine again???
}
}
In the TypeScript, I'm debouncing the ngModelChange handler to give Angular a chance to change the form.dirty value before I check it. This is because ngModelChange gets triggered before the NgForm object has been modified.
If !estimate, because estimate === "", then set it back to its original value of undefined. In this case, the form should look exactly like it did before any user-input had occurred.
However, when I put a breakpoint on the line right above the comment and I output form.dirty to the console, the NgForm never changes dirty back to false.
Is it possible to determine if the form looks exactly like it did before any user-input?
Obviously, I can write my own dirty logic, but wouldn't that mean that NgForm is kind of useless? There's got to be something I'm missing, right? How could dirty not mean dirty?
I've taken a look at some other SO questions -- the first one being similar but definitely not the question I am asking. They are asking if this is intentional -- I don't care; I'd like to know how to accomplish the goal above.
Close, but no cigar:
angular2 formcontrol stays dirty even if set to original value
Block routing if form is dirty [ Angular 2 ]
Angular 2 getting only the dirty values in a controlgroup
How do I programmatically set an Angular 2 form control to dirty?
Angular 2.x/4.x & bootstrap: patchValue does not alter dirty flag. Possible bug?
With template-driven forms and a very flat data model, I implemented it like this:
private currentProduct: IProduct;
private originalProduct: IProduct;
get isDirty(): boolean {
return JSON.stringify(this.originalProduct) !== JSON.stringify(this.currentProduct);
}
get product(): IProduct {
return this.currentProduct;
}
set product(value: IProduct) {
this.currentProduct = value;
// Clone the object to retain a copy
this.originalProduct = Object.assign({}, value);
}
But this only works for very simple cases.
As I mentioned in the comments, using reactive forms gives you more flexibility in managing your data model separate from your user entries.
What Was Most Useful
template.html
<form #form="ngForm" (ngSubmit)="handleSubmission($event, {}, form)">
...
<input
#input
type="text"
[name]="item.title"
[attr.name]="item.title"
[(ngModel)]="item.estimate"
(ngModelChange)="handleEstimateChange(item, item.estimate, input, form)"
/>
...
</form>
component.ts
export class LeComponent {
#Input('data') public section: any;
public handleEstimateChange: Function;
private resetFormControl = (input: HTMLInputElement, form: NgForm) => {
var name = input.name, control = form.controls[name];
control.reset();
// control.markAsPristine();
// control.setValue(undefined);
// control.updateValueAndValidity();
};
constructor(private $: Sandbox) {
this.handleEstimateChange = $.debounce(this.handleEstimate.bind(this), (1000*0.2));
}
handleEstimate(item: any, estimate: number, input: HTMLInputElement, form: NgForm) {
if (!estimate) this.resetFormControl(input, form);
(this, item, estimate, input, form);
// Why does form.dirty never change back to pristine again???
}
}
Note
[attr.name]="..." (template.html)
resetFormControl
Basically, simply deleteing the value was not enough because it was still present on the FormControl object (form.controls). To clear it properly, invoke control.reset() for the individual control -- this in-turn invokes .markAsPristine() which communicates to the parent NgForm. Also, input.name was empty as it was only represented by ng-reflect-name unless [attr.name] elucidated the same value -- [name] is really just there because its required by Angular.
Now, anytime an <input /> value changes -- and its falsey -- we reset the input ensuring that if all are falsey, Angular will automatically handle the NgForm's dirty-state correctly.
I would like to retrieve the user input from a component within my Java code. Something akin to textbox.text in aspx/.NET. I am finding the documentation very confusing and my attempts don't compile. Is there a way?
<tr:inputDate id="date" required="true"
inlineStyle="color:rgb(0,58,117); font-weight:bold;"
value="#{processScope.benefit.serviceDate}"
immediate="false"
onchange="submit();"
label="#{mb_ResourceBean.res['claim.serviceDate.label']}">
<tr:convertDateTime pattern="yyyy/MM/dd" secondaryPattern="yyyyMMdd"
type="date"/>
<tr:validateDateTimeRange minimum="#{bk_ClaimBean.minDate}"
maximum="#{bk_ClaimBean.maxDate}"/>
</tr:inputDate>
Poor half-attempt to grab input:
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
UIXComponent component = viewRoot.findComponent("date"); //does not compile
I'm not sure what you are trying to achieve, but since you already have a value binding (#{processScope.benefit.serviceDate}) and you have onchange="submit();" in your <tr:inputDate> it looks like you want to use a valueChangeListener.
You need a method to handle the value change event in your bean, for example:
public void dateChanged(ValueChangeEvent event)
{
System.out.println("New value: "+ event.getNewValue());
System.out.println("instanceof Date: "+ (event.getNewValue() instanceof Date));
}
In your jspx you have to add the listener. Also you might want to use autoSubmit="true" instead of onchange="submit();", for example:
<tr:inputDate value="#{myBean.myDate}"
valueChangeListener="#{myBean.dateChanged}"
immediate="true" autoSubmit="true"/>
The code in your question does not compile since viewRoot.findComponent() will return a UIComponent. You need to cast it to UIXComponent.
Also, you need to take the naming containers into account. You will need to use something like: viewRoot.findComponent("formId:date");. In this case formId is the id of your <tr:form>.
I am using rich faces select component.
I want dynamic values when user manually type some thing in the select component.
<rich:select enableManualInput="true" defaultLabel="start typing for select" value="#{supplierSearchBean.userInput}">
<a4j:ajax event="keyup" execute="#this" listener="#{supplierSearchBean.userInputChange}"/>
<f:selectItems value="#{supplierSearchBean.selectOptions}" />
</rich:select>
Java code as follows
public void userInputChange(ActionEvent ae){
Map map = ae.getComponent().getAttributes();
System.out.println(map.toString());
}
public void setUserInput(String userInput) {
System.out.println("userINput = " + userInput);
this.userInput = userInput;
}
Here i found 2 issues
1st: setUserINput always print empty string when user type value
2nd: listener method never get call.
any help ?
The problem is most probably that there is no selected value while the user types, and this component restricts the allowed values to the specified select items. A partial input is thus not valid and cannot be bound to your bean.
I think you could get the expected behavior if you use a rich:autocomplete instead. However, if you want to restrict the allowed values, maybe you can keep your rich:select and listen for the selectitem event.
Override getItems function in richfaces-utils.js file in richfaces-core-impl-4.0.0.Final.jar under richfaces-core-impl-4.0.0.Final\META-INF\resources folder.
Change the condition of pushing items to be
if(p != -1)
instead of
if(p == 0)
This should fix the issue.
I have a scala form with several fields.The fields in the form map to the member variables of a Java class. I want to bind one of the fields(say userId) with a value (I dont want the user to enter values for this field. Instead i want to pass this as a parameter to the scala template). However, i was unable to manually bind a form field. Any help is highly appreciated.
See the sample below for easier understanding :
`#(itemForm: Form[Item], user: User)
#import helper._
#main("Item list") {
#if(user != null) {
#form(routes.Application.newItem()) {
#itemForm("userId") = #user.id /**I want to bind the userId form field */
#inputText(itemForm("title"))
#inputText(itemForm("description"))
#inputText(itemForm("price"))
<input type="submit" value="Create">
}
}
}`
In this case it would be better to pass it as action's argument (remember to modify routes declaration)
#form(routes.Application.newItem(user.id)){
....
you can also just use common html
<input type="hidden" name="userId" value="#user.id" />
edit:
Validation in action.Note: it doesn't make sense to display errors on the page next to hidden field, so you do not need placeholders for error messages. It's up to you to pass VALID value into the hidden field. Displaying validation errors to user who can not change the value of hidden field is bad conception.
public static Result newItem(){
Form<ItemModel> itemForm = form(ItemModel.class).bindFromRequest();
if (itemForm.hasErrors(){
return badRequest(newItemView.render(itemForm));
}
itemForm.get().save();
return ok("Your new item is saved...");
}
I'm trying to employ a technique that I came across that seems quite clean.
Previously, my Partial had the loop inside of it. I was looping through the mode within the Partial... but then I came across an example where the foreach loop existed in the main page, while the partial was just the meat of the loop.
They accomplished it like so:
<% int index = 1; // iteration
foreach (var item in Model.Deal) { %>
<% Html.RenderPartial("DealList", item, new ViewDataDictionary {{ "index", index }}); %>
<% i++; // increase the interation
} %>
But in my example, I'm using a ViewModel, and now that I'm in the partial, I can't access "item" like I used to be able to. Instead my only option is Model.Deal ...
What is the point of passsing "item" with the RenderParial helper if I can't access it by saying item.StoreName? Note, both the View and the Partial are strongly typed to the same ViewDataModel.
Inside of the partial "DealList" your model will be whatever item is in the main view. Inside of the partial view, Model.Deal refers to a Deal object inside of item (from the main view).
This means that your StoreName property will be accessible as Model.StoreName within your partial view.
As a side note, I put together an extension method to deal with rendering of multiple partial views so as to not require the looping.
The new method is called RenderPartials:
public static void RenderPartials(this HtmlHelper helper, string partialViewName, IEnumerable models, string htmlFormat)
{
foreach (var view in models.Select(model => helper.Partial(partialViewName,model)))
{
helper.ViewContext.HttpContext.Response.Output.Write(htmlFormat, view.ToHtmlString());
}
}
Using this method you can simple say:
<% Html.RenderPartials("DealList",Model.Deal); %>
inside your main view, without the loop.
There's some more information about this here which explains more about the htmlFormat parameter etc.
Hope this is helpful to you.
#model IEnumerable<dynamic>
#foreach (dynamic m in Model)
{
#Html.Partial(MVC.Lists.Messages.Views._SingleMessage, (object)m)
}