YUI Datatable: rowsPerPageChage Event: Get Drop Down ID on change - event-handling

I'm reposting this question from an earlier post because when I originally asked it, it was unclear. I wasn't sure what I actually needed, and that caused the responses I was getting to be not applicable.
Original: YUI Datatable - Get ID of DOM Element after page has loaded and use it in other YUI events
My question is this:
I have a YUI Datatable. I have a rows per page drop down. I need to create an event, or event handler, or utilize one that exists, that will handle the following:
When(ever) the drop down displaying the rows per page changes, the event handler should get the id of that drop down and pass it to another function to use as an argument. My datatable has two rowsPerPageDropDown (aka rppDD) elements. I need this functional for both of them.
Preferably, it would also do this when the page loads, but for now that's extra credit.
I know that the id of "top" rppDD element is currently "yui-pg0-0-rpp12" but my problem extends from the fact that if I add any code to this page, that id will change (to "-rpp13" or something similar). That throws off the rest of my functions. So I want to just grab the id (whatever it may be) at run time and use it that way rather than hard coding it in.
The second function will run immediately after the drop down changes. It will use the id of the drop down to get the currently selected value and assign it to a variable to be used with a third function.
Here's what I have so far: In the earlier thread, it was suggested that I use the event rowsPerPageChange. This works only to a certain degree. Placing a simple "hello world" alert within that event handler proves that it only alerts when the page loads. Whenever I click and change the drop down to something else it no longer alerts.
Below is the function(s) and code I'm using to test this:
var getRppValue = function() {
YAHOO.util.Event.addListener("rowsPerPageChange", getRppValue.prototype.handleOnAvailable());
}
var rppDD_ID = "";
getRppValue.prototype.handleOnAvailable = function() {
alert("hello world");
alert(this.id); //should alert "yui-pg0-0-rpp12"
//rppValue = this.id;
}
var rppEvent = new getRppValue();
Near as I can tell this event only fires/gets handled when the page initially loads. At that time, the first alert alerts "hello world" as expected. The second alert shows "undefined". The intention is that the second alert should alert whatever the id of the rppDD element is ("yui-pg0-0-rpp12").
For reference, the function I plan on passing the id into is as follows. It is intended as I mentioned above to assign the current value of [the|either|both] rppDD element(s) to the variable oRPP. It then calls the endDrag() function (which utilizes oRPP):
If I were to hard code the id it would be:
function getRPP_0(){oRPP = g("yui-pg0-0-rpp12").value;endDrag();};
I want it to by dynamic:
function getRPP_0(){oRPP = g(rppDD_ID).value;endDrag();};
Any help / suggestions are appreciated.

As we saw on the chat, you had this:
var onRPPChange0 = YAHOO.util.Event.addListener("yui-pg0-0-rpp12", "change", getRPP_0);
var onRPPChange1 = YAHOO.util.Event.addListener("yui-pg0-1-rpp24", "change", getRPP_1);
function getRPP_0(){oRPP = g("yui-pg0-0-rpp12").value;endDrag();};
function getRPP_1(){oRPP = g("yui-pg0-1-rpp24").value;endDrag();};
And you wanted to be able to access the element being changed in the function.
Fortunately, event handlers provide the element on which the event is happening in the this object.
So, this works:
var onRPPChange0 = YAHOO.util.Event.addListener(
"yui-pg0-0-rpp12", "change", function() {
// Notice that "this" is the element on which the event was fired
oRPP = this.value;
endDrag();
};
This way, you can generalize your function easily without hardcoding the IDs.

Related

Running into an issue with a mutation and component flickering with react-query

So, I am making a query everything my context API is updated via a form selection update..
So, order of operation is like so.
User makes a change to a form by selecting (one of possible many) from dropdown.
Change updates "context api" which resaturates the parent component.
Because the form key/values changed, I fire a mutation.
Mutation returns a value. So far, great.
But, when I repeat step #1 - #4, another component flickers with that updated value because at some point the "const" that is expecting a value is undefined... THEN, it has a value..
So, like so..
has a value...
...query api call...
has no value
...returns query
has a value
const ProductPage = (props) => {
const { question } = useContextStateWhatever();
/* Queries */
const { data = {}, isFetched } = useProductUpdatePrice({ questions });
const value = derivePriceFromResponse(data.products);
return (
<SomeComponentRendered value={value} />
)
So, you can see between the "old value" and request in query, that the passed "value" will be undefined. Then query returns, updated value.
I was hoping the query will return any previous value, but the "queryKey" changes with every selection of the form. Deep queryKey.
I was hoping I wouldn't have to then put this value into local state from within a useEffect, or use useRef and create hook to hand back "previous" value until new value is ready.... That's not what react-query is for, right? I mean, shouldn't I be able to make a query call whenever the "context api" changes, and not expect this latency diff of undefined. Any strategies to over come this?
Since the "queryKey" is different (mostly for normal form interaction) for each query, I can see how it can't hand back a previous value until it resolves etc.. any ideas?
Any thoughts?
I think the keepPreviousData: true option is what you are looking for. If the query key changes, you will the get the data from the previous query key, along with an isPreviousData: true flag. The background update will still happen, and then you’ll get the data for the new query key once it arrives. The query will stay in isSuccess status the whole time.

Does model.getProperty() return a live object for objects that are members of an array?

I get an object from within an array in my model (a JSONmodel type) which is
{
"task": [
{
"dbid": 465,
"bk_cnt": 11,
}, {
"dbid": 472,
"bk_cnt": 16,
}
]
}
I bind this model to a table and connect the bk_cnt up to an objectNumber in a cell. No problem so far.
In code I want to change the value of the first bk_cnt value from 11 to 20 on press of a button. Inside the event I have:
var model = this.getView().getModel() // get the model
var tasks = model.getProperty("/task"); // get as a JS object
tasks[0].bk_cnt = 20 // update the model...will it update the view?
// model.refresh() // it will if this is uncommented.
Problem: Though it is bound to the view, the displayed value of bk_cnt does not change. if I add model.refresh() it does. This code is extracted from a larger section and one of the larger features is sorting by column click. When I click a column to re-sort (no change to the model), the value 20 appears.
What gives?
Musings: I have read that the model.getProprty() function returns a javascript object with a live reference back to the model, and that a change to the value of the object will automatically be reflected in the view for any bound controls. Does this statement fall down on array attributes ?
EDIT: Still feeling around the issue I find that
model.setProperty("/task/0/bk_cnt", 20)
Does not require a model.refresh() to update the view. Not a total surprise as this command is directly acting through the model. This leaves me thinking that the 'live' object returned by getProperty() is only live when it is a primitive datatype like a string or integer, but not for a JS object. Or am I missing something ?
EDIT 2: #Ash points out in his answer that there is a further approach which is to access the JS object from the model property, set whatever attributes need to be updated in the JS object, then replace that into the model, e.g.
var tasks = model.getProperty("/task");
tasks[0].bk_cnt = 20
model.setProperty('/task', tasks)
Second edit done to complete the trio of approaches for future readers.
The Model object is an abstraction layer ON TOP of a javascript object. There is no way that a change within an object is notified anywhere. You need to explicitly trigger the notifications through model.refresh() or model.setProperty().
So both of your solutions are valid, another one (which I favor) would be
var tasks = model.getProperty("/task");
tasks[0].bk_cnt = 20
model.setProperty('/task', tasks)
But this actually depends on how you bind your model to your UI objects :)

Handling more complex forms

In my current project I have to deal with more complex forms. Fields (i'll name them 'A' and 'B') are automatically filled if a specific field (i'll name that one 'C') received user input. But also if the user inputs data into field A, the fields B and C are automatically filled out.
(This is only a simple example, the current logic is a bit more complicated)
What I have to take care of is that no cycles happen (C -> A -> C -> A -> ...). So I need to now if the current value change was due to user input or another field that had received input and then triggered the value change of the current field. And I also need to now in the second case which field exactly triggered the value change because then I must trigger other specific actions corresponding from who/what triggered that value change.
Is there a general approach in Vaadin to deal with this kind of form
structure? The problem at the moment is that I simply don't now who
or what triggered what ValueChangeEvent.
Are there frameworks to deal with this or am I overlooking an existing Vaadin pattern?
Handling of valueChange events in Vaadin is a bit of pain, since it always fires, no matter if the user has changed something, or the application has used setValue(....) on the component.
The only solution for this is to remember when you do a setValue(....) in your application and then disable the trigger code in the other components.
For example in this case (endless loop):
field1.addValueChangeListener( field2.setValue('Updated by field1');
field2.addValueChangeListener( field1.setValue('Updated by field2');
Change it that way:
boolean inTrigger= false;
field1.addValueChangeListener(
{
if (!inTrigger)
{
inTrigger= true;
field2.setValue('Updated by field1');
inTrigger= false;
}
});
field2.addValueChangeListener(
{
if (!inTrigger)
{
inTrigger= true;
field1.setValue('Updated by field2');
inTrigger= false;
}
});
That way you can prevent update loops and let execute your code exactly once.

Is there a way to get the original value of a cell in onEdit()?

I'd like to know if there's a way to get the original value of the cell from within the onEdit() event.
For example:
Cell A1's current value is "hello"
I edit A1 it by changing it to "world"
Right now, when I try to get the value from the active range, I'd get "world"
But I would also like to have the possibility to get the original value, i.e. "hello". Is that currently possible?
You can use onEdit(e) and e.oldValue if you're dealing with a single cell. The example below adds the original value to A1 when any cell is edited. 'undefined' if the cell was blank.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getActiveCell();
var origValue = e.oldValue
sheet.getRange('A1').setValue(origValue);
}
The only code that would come close to this is to use an onOpen exit to save
the initial value. The initial value could be saved in several ways. There
are "user properties". I don't know how they work, yet. I am new to this.
You could also use a "hidden" sheet to save the value, in the "onOpen" exit.
There may be other ways, that I don't know about.
The problem becomes more difficult with an increasing number of cells for which
you want to save the original value.
By-the-way, you should understand that the "onOpen" routine fires at the time
the spreadsheet is opened. It so happens, that the end-user also has access and
can change cell values before the onOpen handler finishes its execution. You may
not capture all of your initial values.
One final thing you should know. The onEdit trigger is NOT fired when an UNDO or REDO
event occurs. The cell's contents could change and you will not know it.
I don't know how a validation routine works. If the routine rejects a value, will
the spreadsheet restore the original value? If it does, then this might get around
the onOpen problem. If it only tells the user the value is invalid, it will not be
of much help.
A really round about way that may work, but is very complicated is to save the image
before the spreadsheet closes. You post all the "after" images to a second spreadsheet.
Then in your onEdit handler you look at the corresponding cell in the other spreadsheet.
You then decide to restore the previous image or allow the new image to proceed.
Lastly a wild idea of using a data table in place of the second spreadsheet.
I am just learning about all of these concepts, so don't ask me how to implement them.
I just understand that they MIGHT be possible. For coding and support purposes they
may not be the best options. But since the current script service does not provide
before image access, it is about the best I could do. You have to understand that this
google interface is a client-server application. Your scripts run on the server. The data changes occur in the "clients" (end-users) browser.
One final note: the onEdit trigger does not fire for an UNDO or REDO change to a cell.
So the cell could change and your script is not aware of it.
I don't think that's possible.
I imagine you could get that functionality by having a exact copy of your sheet on a second sheet that updates automatically when your 'onEdit' functions ends.
Until that update, data on the second sheet will have the former value.
A bit tricky but why not ?-)
EDIT : seems to be the 'question of the day', see this post and Henrique Abreu's pertinent comment.
When you change the value of a cell diagrammatically, you can use the setComment method to store the original value as a comment in that cell.
What you basically need to do is to create a shadow sheet (which you can protect and hide or even have it in a totally separate spreadsheet) and use the IMPORTRANGE function to get the values of the original sheet into the shadow sheet (This gives enough delay time to get the old value that was in the cell before it got edited).
=IMPORTRANGE("enter your original sheet's ID","enter the range you wish to get from the sheet")
Please note that using this code, when editing multiple cells at the same time, the function will only work on the first cell.
function onEdit(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var originalSheet = sheet.getSheetByName('Original');
var shadowSheet = sheet.getSheetByName('Shadow');
var editedCell = originalSheet.getActiveCell();
var cellColumn = editedCell.getColumn();
var cellRow = editedCell.getRow();
var oldValue = shadowSheet.getRange(cellRow, cellColumn).getValue();
var cellValue = editedCell.getValue();
var editorMail = Session.getActiveUser().getEmail(); \\getting the editor email
if ("The condition you want to meet for the onEdit function to activate"){
editedCell.setNote(editorMail + "\n" + new Date + "\n" + oldValue + " -> " + cellValue);
}
}

how to send searching criteria to server and showing searching result in another page?

very simple situation, one search page with several searching criteria, when user fill in and press 'search', the searching criteria is pass to server and retrieve database and put the result in a arrayList, then the server redirect the page to result page, showing the searching result.
I do not know how to do the final step, "show the result in result page"
if using GWT-RPC method,
is we get the result arraylist in onsuccess method of callback object then jump to another page in onsuccess method?
but I do not know how to implement this, especially the part "send the result and jump to another page"
if I do this using PanelForm method, I also stuck on the step how the result (an arrayList) pass to the show result page? or how the show result page get the search result in server?
sorry for my english,
you'll get the list in onsuccess method
public void onSuccess(List list)
{
List resultList = new ArrayList<com.shared.PanelFormVO>();
for (int i = 0; i < list.size(); i++) {
PanelFormVO ld1 = (PanelFormVO) list.get(i);
resultList.add(ld1);
}
cellTable.setRowData(resultList);
}
this code will show you how to put the data in cell table..
else u can use the list to use the data