how to capture onclick for wicket jquery ui spinner - javascript

How can I capture the onclick event for the up & down buttons on a spinner component from JQuery?
I am able to capture the onchange for the associated textfield with the following code, but the up & down spinner buttons are not triggering the event:
Spinner<Integer> psbBudget = new Spinner<>("psbBudget", new PropertyModel(psb,"psbBudget"), Integer.class);
psbBudget.add(new AjaxFormComponentUpdatingBehavior("onchange") {
#Override
protected void onUpdate(AjaxRequestTarget art) {
Integer inputS = (Integer) getFormComponent().getConvertedInput();
BigDecimal spinnerTime = BigDecimal.valueOf(inputS);
unallocatedTimeMap.put(psb, unallocatedTimeMap.get(psb).subtract(spinnerTime));
art.add(budgetListViewContainer);
}
});
listItem.add(psbBudget);
li.add(new Label("remainingBudgetLabel", new Model(unallocatedTimeMap.get(psb))));
Just to make it more difficult on myself, this spinner is contained in a ListView as the number of budget items is variable. I am getting the remainingBudgetLabel to reflect the changes that are made within the text field, but not the changes made using the spinner buttons!
I have started exploring injecting my own javascript with the following lines:
// behavior to capture changes made using spinner buttons (doesn't work!!!)
add(new Behavior() {
#Override
public void renderHead(Component component, IHeaderResponse response) {
super.renderHead(component, response);
response.render(OnDomReadyHeaderItem.forScript("$('.ui-spinner-button ui-spinner-up ui-corner-tr ui-button ui-widget ui-state-default ui-button-text-only').click(function() {$(this).siblings('input').change();})"));
}
});
Here is the relevant section of the declared html:
<table>
<tr>
<td/>
<th>Budget</th>
<th>Remaining</th>
</tr>
<tr wicket:id="budgetListView">
<th wicket:id="budgetLabel">Budget
</th><td><input wicket:id="psbBudget" type="text" style="width:3em" maxLength="2"/>
</td><td wicket:id="remainingBudgetLabel"/>
</tr>
</table>
So I guess this is somewhat of a two part question:
1 - Is there any hope of this javascript injection working (I am just getting my feet wet with javascript) or is there a way to do this more correctly within Wicket?
2 - If javascript is the only way, how can I correctly find the elements when I can't control the id attribute of the generated jquery (or can I control that somehow?)?
I am using the wicket-jquery-ui 6.2.1 library with wicket 6.6.0. Thank you.
EDIT
The generated html I posted previously (now removed) was from right clicking and selecting viewSource, but does not show the actual generated html from jquery. Please see below for a screenshot from the F12 Developer Tools in IE9 that shows the generated html for the spinner includes the original <input> plus two generated <a> tags for the spinner buttons.

I just saw this post...
Just to say that you had 2 other options:
1/ You have you own extended spinner with:
#Override
protected void onConfigure(JQueryBehavior behavior)
{
super.onConfigure(behavior);
behavior.setOption("onspinstop", this.onStopBehavior.getCallbackFunction());
//onStopBehavior is an JQueryAjaxPostBehavior, see how AjaxDatePicker works for instance
}
The second option is to ask for an AjaxSpinner, because it makes sense, either through the github project or the google group:
https://github.com/sebfz1/wicket-jquery-ui/
http://groups.google.com/group/wicket-jquery-ui/
Best regards,
Sebastien.

As much as I hate to answer my own question, here it is:
I was able to capture the events with the following code. The "onchange" captures the event when someone manually enters a number in the field, the "onspinstop" captures the event after the component has been updated by clicking the up/down arrow:
Spinner<Integer> psbBudget = new Spinner<>("psbBudget", new Model(allocatedTimeMap.get(psb)), Integer.class);
psbBudget.add(new AjaxFormComponentUpdatingBehavior("onchange") {
#Override
protected void onUpdate(AjaxRequestTarget art) {
Integer input = (Integer) getFormComponent().getConvertedInput();
// Do whatever with updated input //
art.add(remainingBudgetLabel,remainingBudgetLabel.getMarkupId());
}
}
psbBudget.add(new AjaxFormComponentUpdatingBehavior("onspinstop") {
#Override
protected void onUpdate(AjaxRequestTarget art) {
Integer input = (Integer) getFormComponent().getConvertedInput();
// Do whatever with updated input //
art.add(remainingBudgetLabel,remainingBudgetLabel.getMarkupId());
}
}
I was able to figure this out after looking at the API documentation for the JQuery UI Spinner component then trying every possible combination of the event strings. To do this correctly you have to put the string all in lowercase and add "on" string to the beginning of the event name.
One additional thing that I learned during this exercise was that I can update (I think I am actually replacing them?) individual components within a listview by calling art.add(component, component.getMarkupId());. This is SO much better than what I was doing before with listView.setList(updatedList) and art.add(listViewContainer);

Related

HtmlUnit not showing all injected JavaScript code

The goal is to download a file from a website using HtmlUnit. The download link is generated in JavaScript and dynamically injected into a dropdown menu, based on a previous selection in another dropdown menu. Both dropdown menus are dynamically injected via JavaScript and have the same element structure.
So in general, when loading the page, it shows only the first dropdown list. This sample shows the initial element structure when the page is loaded. When selecting an item from that list, the second dropdown list appears and the element's source structure has been updated to this. When clicking the second dropdown list, the page shows a list with several options containing a direct link to a file. This example shows the selection of the first dropdown list is made, showing the options of the second dropdown list (with a green download icon). At this moment, the source has been updated to with this code (i.e. similar to the previous div). Clicking on any of the list items will start an immediate download of the required file.
What happens in my HtmlUnit application is, when I trigger the same steps until the second dropdown list should appear, the div with id 'formatSelect' stays empty. It looks like the JavaScript code is not being executed for that part only, while it does so for the first part.
A brief sample of my code:
private static final String URL = "https://some.url.org/";
private static final String xpathDeltaSelect = "div[#id='div1']";
private static final String xpathFormatSelect = "div[#id='div2']";
private static final String xpathDropDownToggle = "div[#class='dropdown-toggle']";
private static final String xpathSearchButton = "div/input[#type='search']";
private static final String xpathListBox = "div/ul[#role='listbox']";
webClient_ = new WebClient(BrowserVersion.CHROME);
webClient_.getOptions().setRedirectEnabled(false);
webClient_.getOptions().setDownloadImages(false);
webClient_.getOptions().setThrowExceptionOnScriptError(false);
webClient_.getOptions().setThrowExceptionOnFailingStatusCode(false);
HtmlPage page = webClient_.getPage(URL);
webClient_.waitForBackgroundJavaScript(JAVASCRIPT_TIMEOUT);
final HtmlDivision divDeltaSelect = selectWrapper(page).getFirstByXPath(xpathDeltaSelect );
final HtmlDivision divDeltaDropdown = divDeltaSelect.getFirstByXPath(xpathDropDownToggle);
final HtmlInput inputDelta = divDeltaDropdown.getFirstByXPath(xpathSearchButton);
inputDelta.focus();
final HtmlUnorderedList ulDeltaSelect = divDeltaSelect.getFirstByXPath(xpathListBox);
Iterator<DomElement> iterator = ulDeltaSelect.getChildElements().iterator();
// Iterate to the desired item and 'click'
...
page = li.click();
break;
}
// So far, everything goes well.
final HtmlDivision divFormatSelect = selectWrapper(page).getFirstByXPath(xpathFormatSelect);
System.out.println(divFormatSelect.asXml());
// At this point, divFormatSelect is still empty...
The output of the sysout at the end is the following:
<div data-v-0d6d77a2="" id="formatSelect">
<!---->
</div>
The selectWrapper method is briefly doing the following (because there are 3 similar "selectWrapper" divs that return different data files, but I only need the first one):
final List<DomElement> elements = page.getElementsById("selectWrapper");
...
return elements.get(0);
I did notice that the initial page load at line
HtmlPage page = webClient_.getPage(URL);
throws the following JavaScript error:
com.gargoylesoftware.htmlunit.ScriptException: missing ) after formal parameters (https://some.url.org/path/to/js/javascript.js#1)
... + stacktrace
Could this be related to this bug? However, I do not understand why the first injected code can be retrieved, but not the second part, while the browser interface does the processing correctly. Am I missing something?

How to two-way bind a checkbox using Angular?

I currently have an accordion with a bunch of options in the form of checkboxes. The user can select the checkboxes as expected however, I want to already have some of those checkboxes checked depending on certain conditions. The issue is sometimes that is determined after the page has loaded. Below are simplified examples to demonstrate my code (my code is for work and would not be able to share due to confidentiality issues).
My HTML looks like this:
<div class="row">
<div "ngFor="let value of filteredPeople" >
<div>
<input type="checkbox" (click)="selectPeople(value)" [checked]="checkedPeople.get(value)">
{{ value }}
</div>
</div>
</div
My Javascript:
public checkPeople() {
this.selectedPeople.forEach(element => {
this.checkedPeople.set(element, true);
});
}
To explain some variables and methods:
Variables:
filterPeople - a string array of all possible people
checkedPeople - a map with a KVP of string (the people) and boolean (whether or not their checkbox is checked)
selectedPeople - a string array of people whose checkboxes I want already checked
Methods:
selectPeople - checks the corresponding checkbox when user clicks on it
checkPeople - a method called when I want the specific checkboxes checked (these specific checkboxes change based on other factors so I cannot hard code it)
For some reason my checkPeople method does not seem to select the expected checkboxes, I am not sure why but I have a feeling it is to do with the fact that I have used "[checked]" in the HTML and that it should be something else. Can someone clarify the issue for me and help me identify a fix? (Note: as the title suggests, I am using Angular)
Edit:
I have just debugged my code and added breakpoints, the checkedPeople map has the correct mapping of people to true for each of the elements in selectedPeople which shows that the checkPeople method is working as expected. Therefore the issue must be with the [checked] attribute if I'm not mistaken. I cannot see why it wouldn't work though.
You should use [ngModel]="checkedPeople.get(value)"
instead of [checked]="checkedPeople.get(value)"
to initialize the checkbox and
(change)="checkUncheckPeople(value, $event)"
to update the value when you check or uncheck it, where
checkUncheckPeople(value, e) {
this.checkedPeople.set(value, e.target.value);
}
So, in conclusion, your HTML input element will be:
<input
type="checkbox"
[ngModel]="checkedPeople.get(value)"
(change)="checkUncheckPeople(value, $event)"
/>
If you choose to use an object instead of a map then you can also directly use
[(ngModel)]="checkedPeople[value]"
to two-way bind the variable

Angular / HTML clear input events

I am working on an Angular app and I seem to have stumbled upon a small bug/problem. I have 4 clickable areas in my html and each click calls a function of the component's .ts script. So far, so good. I want to make each area only be clickable once, however this doesn't seem to work the way I am doing it (and I do not quite understand why).
clicked(event: Event): void {
// Get coordinates of clicked cell
var elementId: string = (event.target as Element).id;
if(this.answersGiven.includes(elementId)) {
console.log("included");
return;
}
this.answersGiven.push(elementId);
And the html
<table>
<tr>
<td id="A1" (click)="clicked($event);">
</tr>
So after the first click, the answer should be pushed into the array which is working just fine. However after the second click on the same cell it is not jumping into the if condition. When clicking a third time on the same cell, it works however. When i log the events, the second time I only get "" instead of the element id. My guess is that this could have something to do with some sort of buffer or that the button is pushed down and stays down but I couldn't find anything realted to that.
Glad for any help, thank you :)
You should try this:
HTML:
<table>
<tr>
<td (click)="clicked($event, 'A1');">
</tr>
TS:
clicked(event: Event, cod: string): void {
// Get coordinates of clicked cell
var elementId: string = (event.target as Element).id;
if(this.answersGiven.includes(cod)) {
console.log("included");
return;
}
this.answersGiven.push(cod);
the Angular way of build your HTML have probably changed your <td id="A1", check into your browser developer tool if the ID keeps the same.

Adding views programmatically, then referencing those views.

I'm a novice in the java world, so thanks in advance for the help.
What I am trying to do is this:
I have two EditText fields and a Button. When I hit the button, I want to take the contents of the two fields, combine them and display them below button. The fields are cleared. Then if they are filled again and the button is pushed, combine the fields and display them below previously generated textview.
Example:
Before Button Click:
eT1___ eT2____ |Button|
After Button click
eT1___ eT2____ |Button|
eT1-eT2
After 2nd Button click
eT1___ eT2____ |Button|
eT1-eT2
eT1-eT2
And so on however many times the button is clicked. What I need help with is the new views that are being added. Currently I am using a Relative Layout. What I am trying to figure out is how to reference the new textView's that I am creating within the code so that when new views are added, they can reference the previously added view.
This is what I've been attempting at the moment:
private TextView createNewTextView(String desc, Double cost){
RelativeLayout.LayoutParams lparams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);;
TextView newTextView = new TextView(this);
if (i==1) {
lparams.addRule(RelativeLayout.BELOW, mButton.getId());
}
else {
lparams.addRule(RelativeLayout.BELOW, mLayout.getId());
}
lparams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
newTextView.setLayoutParams(lparams);
newTextView.setText(desc + " - $" + cost);
newTextView.setTag(i);
i++;
return newTextView;
}
I was trying to use "i" as an incrementing variable that I could use to reference the previous view by except on the first pass when it the new view references based on the button.
Any help would be greatly appreciated. Thanks in advance and for everything I've lurked already!
Create a member variable of ArrayList of TextView :
ArrayList<TextView> textviews = new ArrayList<>();
and then in your createNewTextView() method, store the reference of TextView you are adding:
textviews.add(newTextView);
So the TextView you've added at the first will be at index 0 and so on. Then you can easily reference your TextViews.
Suppose you want to get the second TextView,
TextView secondTv = textviews.get(1);
Just add your textviews to a global list and find them based on the tag from there.

How to add asp button to dynamically genreated control

I have a control that overrides Render() and creates its HTML dynamically,
here is a simiplified version of it:
public class CReportBillReadings : Control
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
writer.Write(Html);
}
private string Html
{
get
{
// render result table
var sb = new StringBuilder();
sb.Append("<ul id=\"export\"><li><img src=\"/resources/images/pdfIcon16x16.gif\" /></li></ul><div class=\"clear\"></div>");
And so on.
What it actually does is draw a table according to the given data.
I want to add an asp button to the html ,
so that I can register to its event on the server side.
The only ways I found to do this is:
Add this button to a place holder - not applicable here because the entire HTML is generated dynmically.
Add a jquery button - but I need to handle the event on the server side.
I read about a promising lead here:
http://www.evagoras.com/2011/02/10/how-postback-works-in-asp-net/
But I still can't figure out how to use it- because in the examples I've seen the button is still declared in .aspx and not dynmically in the code.
You can inherit your control from Button control instead of Control. In this case you will have events and all other properties of button. And you can also render table in overrided Render method.

Categories

Resources