Issue with partial refresh triggered twice - javascript

I have a dojo button bar which is bound to a csjs function. This function does a partialrefreshget() on a datable control. The datatable control contains a view as its datasource.
In the this.keys property I have defined some logic to see if the partialrefresh was triggered by checking for the context.getSubmittedValue(). While experimenting with this technique I noticed that the following code is triggered twice.
<xp:this.keys><![CDATA[#{javascript:
var vec = new java.util.Vector()
vec.add("category");
if(context.getSubmittedValue()!=null){
var x = context.getSubmittedValue().trim();
print("--")
}
return vec;}]]></xp:this.keys>
the print statement is printed twice to the console and the logic is therefore triggered twice. Can someone explain to me why this happens and what I can do about it? Should i check for submittedvalues somewhere else or?

I think if you implement a phase listener to print out each phase step, you'll see that this.keys is evaluated twice during the LifeCycle. Probably once during Render Response, and the other during Restore View or something. I would avoid putting application logic within property calculations as it can be triggered at times you would not think it should be unless you are very in tuned with the application lifecycle.

I actually see the submit two or three times on some controls. I have heard that it is an anomalie in the JSP engine that has not been resolved.
What I do is write the vec to a request scope variable after it is computed. then add logic before it is computed to fetch the request scope variable and if it exisits, return it instead of recomputing the value.

After a bit of testing i gave up calling my own partialrefreshget method.the extlib dojo toolbar contains a onclick event which is triggerd when on a node the submitvalue is set. In this onclik event i added code like
Var v = context.getsubmittedvaleu();
If("action".equals(v)){
// do stuff that changes the dataset..
}
The event handler is set to partial refresh a datatable wich receives the new data. This is a much cleaner implementation than checking the submittedvalue in the datasource ( as stated by (jeremy hodge).
This way the datasource is only refreshed once.
As a sidenote i would like add that it would be nice to add such an event directly to the treenode(s) as I would do in standard java swing /awt dev by adding a controllistener to a button.

Related

Overwrite listener without handler reference, is it ok to access the (possibly private) events property on a Ext.data.store?

I'm working on replacing an Ext.data.Store load event handler.
The variable me is different every time within the code block but me.store is the same (obtained via StoreManager.lookup). I want the store event listener to update the various me references. Best way i could find was to add another listener (and delete the old one since i don't need it anymore)
I haven't been able to use un / removeListener i.e. it had not effect.
I've found that i could replace the it by accesing the me.store.events and popping the listener from the load event. However this feels hacky and it might make the code dependant on a specific ExtJS version (4.2) since i don't know if it's a private property or not.
Also me.store.hasListeners['load'] doesn't get notified so it only helps because it removes the actual listener but not in the intended manner. The docs don't mention it, but i'm wondering if it may be an inherited property which can be accessed freely.
Are there any alterntives to the working approach i've come to? Can i remove all event handlers for an event without having a reference to the handler? Or is there a simpler approach i'm missing?
var me = this; // an enriched Ext.form.FormPanel, different every time code runs
me.store //obtained via StoreManger.lookup - so the same every time
me.storeLoaded = function (store, records,successful, opts) {
// some code to select a record from records and use it
me.loadRecord(record);
}
};
if (!me.store.hasListener('load')) {
me.store.on('load', me.storeLoaded);
} else{
//tried this, but it doesn't remove it, probably because me.storeLoaded is different each time (parentForm is different)
me.store.un('load', me.storeLoaded);
//this feels hacky, i couldn't find out if events is a private property
if (me.store.events && me.store.events['load']){
me.store.events['load'].listeners.pop()
}
me.store.on('load', me.storeLoaded);
}
The easiest way to implement adding/removing listeners is using the destroyable parameter as described in the addListener function. That way, you can always be sure which one is removed.
Example:
setActive:function(cmp) {
cmp.myActiveListeners = cmp.eventStore.on({
destroyable: true,
load:cmp.refreshStores,
filterchange:cmp.refreshStores,
scope:cmp
});
},
setInactive:function(cmp) {
Ext.destroy(cmp.myActiveListeners);
},
I cannot recommend to blindly remove ALL listeners, since they may be added by other components (e.g. combobox) that you add later. To track down these bugs will grow you quite some gray hairs.
I was able to find an answer in this article ExtJS overwrite listener:
Sometimes you need to overwrite an event listener in ExtJS. Usually
listeners are registered like this myStore.on('load',
this.myFunction, this); then to remove our previously registered
listener, all we have to do is call un (which is an alias for
removeListener): myStore.un('load', this.myFunction, this);
But, what happens when you don't know what function is registered?
Sometimes you will not have a reference to the original function that
was registered. This situation may arise if there is code that exists
in a different flow or may even come as a package! If that is true,
the you may not be able to get a reference to the javascript function
or edit the existing code. In this case, we will have to look at all
of the functions that are registered for this event. We can then
remove the listeners just for a certain event by calling
clearListeners.
clearListeners was the method i was looking for.
It would seem he uses the events property so i assume it is a valid use. It could be translated in my case to:
me.store.events.load.clearListeners()
However since i will only be using the load event on this particular store, i will simply call on them all.
me.store.clearListeners()
Thanks to Alexander, by suggesting not to remove all listeners that actually helped me find the article. However i will stil go with his solution, even if it polutes the store object because i like it better than clearing all listeners on a store, even if only for a specific event.

Firebase.on() vs GET Request [duplicate]

I'm pretty new to Angular and I'm using firebase as my backend. I was hoping someone could debug this issue. When I first go to my page www.mywebsite.com/#defaultHash the data doesn't load into the DOM, it does after visiting another hash link and coming back though.
My controller is like this:
/* initialize data */
var fb = new Firebase('https://asdf.firebaseio.com/');
/* set data to automatically update on change */
fb.on('value', function(snapshot) {
var data = snapshot.val();
$scope.propertyConfiguration = data.products;
console.log($scope.propertyConfiguration);
console.log("Data retrieved");
});
/* save data on button submit */
$scope.saveConfigs = function(){
var setFBref = new Firebase('https://asdf.firebaseio.com/products');
setFBref.update($scope.propertyConfiguration);
console.log("configurations saved!");
};
I have 3 hash routes say "Shared", "Registration", and "Home" with otherwise.redirectTo set to "Shared".(They all use this controller) Here's the error that occurs: (all "links" are href="#hashWhereever")
1) Go to website.com/#Shared or just refresh. Console logs $scope.propertyConfiguration and "Data Retrieved". DOM shows nothing.
2) Click to website.com/#Registration, console logs $scope data properly, DOM is loaded correctly.
3) Click back to website.com/#Shared, console logs $scope data properly yet this time DOM loads correctly.
4) Refresh currently correctly loaded website.com/#Shared. DOM elements disappear.
Since $scope.data is correct in all the cases here, shouldn't Angular make sure the DOM reflects the model properly? Why is it that the DOM loads correctly only when I am clicking to the page from another link.
I can "fix" it by adding window.location.hash = "Shared" but it throws a huge amount of errors in the console.
FIXED:(sorta)
The function $scope.$apply() forces the view to sync with the model. I'd answer this question myself and close it but I'm still wondering why the view doesn't load correctly when I correctly assign a value to $scope. If Angular's "dirty checking" checks whenever there is a possibility the model has changed, doesn't assigning a value to $scope overqualify?
Angular has no way to know you've assigned a value to $scope.variable. There's no magic here. When you run a directive (ng-click/ng-submit) or Angular internal functions, they all call $apply() and trigger a digest (a check of the dirty flags and update routine).
A possibly safer approach than $apply would be to use $timeout. Currently, if you call a write op in Firebase, it could synchronously trigger an event listener (child_added, child_changed, value, etc). This could cause you to call $apply while still within a $apply scope. If you do this, an Error is thrown. $timeout bypasses this.
See this SO Question for a bit more on the topic of digest and $timeout.
This doc in the Angular Developer Guide covers how compile works; very great background read for any serious Angular dev.
Also, you can save yourself a good deal of energy by using the official Firebase bindings for Angular, which already take all of these implementation details into account.
Vaguely Related Note: In the not-too-distant future, Angular will be able to take advantage of Object.observe magic to handle these updates.

Basic JQuery syntax: What mechnaic is at work in this small (2 line) piece of JavaScript / JQuery

So here' s the piece of code. I'm very new to JavaScript so don't be afraid to explain the obvious
$(".my-css-class").on("click", function() {
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
});
There's an element in the .jsp page that looks like this:
<i class="clickMe"></i>
I know the .jsp creates a link-icon, and that the above JavaScript is an event handler. I know that it passes these 3 values as arguments another JavaScript method:
function doStuff(prop1, prop2, obj) {
if (prop1 == 'foo') {
//do stuff with prop2
}
else{
// do stuff with obj
}
}
It all works fine. What I want to know is what exactly is going on to make it work? I can't find anything in the code that connects what the event-handler returns to the 'doStuff' java-script function.
The names are totally different, so it's not reflection, it can't be parameter matching because there's other functions with the same number and type of parameters in the file, it can't be convention based because it still works if I find/replace the name of the function to gibberish.
I guess basically I'm asking what this line is doing:
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
tl;dr: I'm at a loss, I know how the properties get as far as the onClick event-handler's anonymous function - but how does JavaScript know to pass them as arguments the to the doStuff() function?
the onClick event is a standard event triggered on click of any clickable html element and is automatically raised by the DOM.
You are hooking in to this by listening on any matched ".my-css-class" elements for an onClick Event.
The jquery syntax ".on" has been simplified over time and allows you to hook into any number of events like "submit" - OnSubmit event , or "load" - onLoad Event
Wherever your on("click", myFunction) event hook is picked up, your myFunction will execute.
Looking at your second point...
because it still works if I find/replace the name of the function to gibberish.
The DoStuff function will be found and replaced across all files in your site? or page? or open tabs? , so therefore it must exist somewhere as "doStuff(" or "giberish(".
so when you do a global find/replace, do each one slowly, until you locate it.
Finally, when you do a view source in the browser, this should either explicitly show you the doStuff function, or at the very least give you a clue as to satelite files loaded at runtime, where you can go and investigate.
Use firebug in firefox to debug loaded resources; the ".net tab" to view external loaded resources and the html/javascript they might contain. (for example: your master page might be loading in an embeded resource that contains the doStuff method, becuase of a user or server control reference in that master page)
Also have a look at this:
http://www.developerfusion.com/article/139949/debugging-javascript-with-firebug/
You can step through the javascipt piece by peice until it hits the doStuff method.
Just remember to set at least 1 breakpoint ;-)

setReadOnly causes error when called on instanceReady of CKEditor

I'm trying to set my CKEditor instance to be "readOnly" after the instance has fully loaded but I'm getting a Javascript error: Cannot call method 'setReadOnly' of null. When I dig into it, the error is coming from this line in the ckeditor.js, within the editor.setReadOnly method: this.editable().setReadOnly(a); That means that the editor exists, but the editable method/attribute (on the CKEditor instance) does not.
Below is my code, and I'll explain it a little. My app is a combination of GWT and Backbone. The CKEditor itself is created by the Backbone code but the parent element is in GWT so that's where I initiate the setEnabled action.
private native void setEnabledOnLoad(boolean enabled, String id) /*-{
CKEDITOR.on("instanceReady", function(evt) {
if(evt.editor.name === id) {
Namespace.trigger(Namespace.Events.SET_ENABLED, enabled);
}
});
}-*/;
setEnabled: function(enabled) {
this.editor.setReadOnly(!enabled);
if(enabled){
this.editor.focusManager.focus();
} else {
this.editor.focusManager.blur();
}
}
The Backbone class has a listener for Namespace.Events.SET_ENABLED that triggers setEnabled.
Is there another CKEditor event that I should listen for? There doesn't appear to be an instanceReady event on editable. What am I missing?
EDIT
this.editor is created in the Backbone class render function like this:
this.editor = CKEDITOR.replace(this.$(this.id)[0], config);
The reason I don't add the instanceReady listener right after it's created is because the function setEnabledOnLoad is called in GWT before the instance has been fully initialized. This is a result of having the code in two places. GWT has said "ok, create the instance" but Backbone hasn't finished by the time GWT goes to the next line of code and wants to set it enabled/disabled.
Two years later, but here is my solution. Maybe someone else will find it useful.
As stated above, the event is appearantly triggered before the editable() function is fully set up, and therefore one solution is to simply wait for it to finish before setting it to readonly. This may be an ugly way to do it, but it works.
//Delayed execution - ckeditor must be properly initialized before setting readonly
var retryCount = 0;
var delayedSetReadOnly = function () {
if (CKEDITOR.instances['bodyEditor'].editable() == undefined && retryCount++ < 10) {
setTimeout(delayedSetReadOnly, retryCount * 100); //Wait a while longer each iteration
} else {
CKEDITOR.instances['bodyEditor'].setReadOnly();
}
};
setTimeout(delayedSetReadOnly, 50);
You could try subscribing to instanceReady event this way:
CKEDITOR.instances.editor.on("instanceReady", onInstanceReadyHandler)
However, the editor instance must have been already created by then (inspect CKEDITOR.instances in the debugger).
I'm a bit confused about the difference between editable and editor. Could you show the fragments of your code where this.editor and this.editable get assigned?
[EDITED] I guess I see what's going on. CKEDITOR is a global object, you may think of it as of a class which holds all CKEDITOR instances. Trying to handle events with CKEDITOR.on isn't right, you need to do it on a specific instance (like I've shown above). I assume, "editor" is the ID of your parent element you want to attach a CKEDITOR instance to (please correct me if I'm wrong). I'm not familiar with Backbone, but usually it's done with replace:
var editorInstance = CKEDITOR.replace("editor", { on: {
instanceReady: function(ev) { alert("editor is ready!"); }}});
Here we attach a new instance of CKEDITOR to the editor parent element and subscribe to the instanceReady event at the same time. The returned object editorInstance should provide all the APIs you may need, including setReadOnly. You could also access it through the global CKEDITOR object using the parent element ID, i.e. CKEDITOR.instances.editor. On the other hand, editable is rather a service object available on editor. I can't think of any specific case where you might need to use it directly.
I apologize for never updating this with my solution. I needed to decouple the GWT function further from the CKEditor behavior. So, I added a function in GWT 'setEnabled' that is called from the parent object when it wants to update the enabled state of the CKEditor object.
public void setEnabled(boolean enabled) {
this.enabled = enabled;
toggleCKEditorEnabled(enabled);
}
Then changed the function referenced above 'setEnabledOnLoad' to be 'toggleCKEditorEnabled' which triggers the SET_ENABLED event with the enabled value.
Instead of attaching the listener to the specific instance of CKEditor, I added in to the Backbone MessageEntryView class that is the container of the CKEditor instance. In the initialize function of the MessageEntryView, I added this line
Namespace.on(Namespace.Events.SET_ENABLED, this.setEnabled);
This only works because I have one instance of CKEditor loaded on the screen at any given time. This problem and its solution stopped us from being able to add more CKEditor instances to the page at a time, which is something we discussed before moving on and replacing our whole client with Backbone.

PrimeFaces get the current page number on page change event

I have a primefaces datatable.
I need to know the current page number on page change event using client side API.
I am using,
<p:ajax event="page" oncomplete="myFunction(usersWidget);"/>
Inside myFunction() i have
debugger;
console.log(usersWidget.paginator.getCurrentPage());
The problem is, callbacks inside oncomplete of page event are called before the new page is set (PrimeFaces.widget.Paginator.setPage) on the paginator. I traced this with the debugger.
That being said, i would get the previous page number i was on and not the current page number, inside oncomplete callback.
If i could get a callback after the page is set after i click the page link, i would know the current page.
EDIT: Docs say that its a callback called after ajax completion and after DOM is UPDATED.
then what could be potentially wrong?
Pointers please?
Its strange , cause oncomplete being called after the page was updated...
How about calling oncomplete="myFunction();" without passing the parameter ?
You might be passing the old object (with outdated information) that way... the usersWidget is global variable anyway... ans should be present in your js file
Since it seems that client side api is not synced with the right values
As a workaround you could try to pass the page value from server like this
DataTable dataTable = (DataTable)
FacesContext
.getCurrentInstance()
.getViewRoot()
.findComponent("someOformID:someTableId");
or try, instead of the line above,
PageEvent.getPage(); //PageEvent is an argument to you listener
myPageHolder = dataTable.getPage();
Than place this value to bean property and put it inside some hidden value in xhtml , than update that hidden value with p:ajax update and access it from within js

Categories