openui5 1.38 attach event scrollbar - scrollbar

from the last version update (from openui5 1.36.12 to openui5 1.38.4) the following code is not working anymore:
var myTable = new sap.ui.table.Table();
myTable ._oVSb.attachScroll(function() {
colorTheTableRows();
})
I'm using the "attachScroll" event in order to color the table rows with a specific logic.
Since last openui5 version update I get this error in console:
Uncaught TypeError: Cannot read property 'attachScroll' of undefined
I've tried to debug the problem and it seems that the object _oVSb has be removed from sap.ui.table.Table.
My final goal is to paint the rows with different colors based on the content ... is there any other way to reach this feature?
Thanks

Even i want this event some how came to this thread. i tried #Dopedev solution it was not working then i changed bit in that as below
$("#<tablid>-vsb").scroll(function() {
console.log("Table is scrolled")
});
instead of getting the tbody get the table-id-vsb and attach the scroll function

You can still get scroll event for your table using .scroll() of jQuery.
onAfterRendering: function(){
//Register handler for scroll event
$("tbody").scroll(function(){
// your stuff
});
}
Demo

I know that one of the earlier posts was already marked as the 'right' answer, but it did not work for me, so I thought I would post my working solution, as it might be helpful to others. The following code will work to effectively 'attach' to the vertical scroll event of a table in 1.38:
onAfterRendering: function() {
if (this.firstTime) { //You only want to override this once
var oTable = this.getView().byId("<YOUR_ID_HERE>");
//Get a reference to whatever your custom handler is
var oHandler = this.handleScroll;
//Store a reference to the default handler method
var oVScroll = oTable.onvscroll;
oTable.origVScrollHandler = oVScroll;
oTable.onvscroll = function(i) {
//Call the 'default' UI5 handler
oTable.origVScrollHandler(i);
//Call your handler function, or whatever else you want to do
oHandler();
};
this.firstTime = false;
}
},

var myTable = new sap.ui.table.Table("myTable");
After rendering:
sap.ui.getCore().byId("myTable-vsb").attachScroll(function() {
colorTheTableRows();
})

Related

How to attach a callback to a custom confirmation dialog in Google App Maker?

I am creating a custom confirmation dialog in Google App Maker and would like the Confirm button to call a passed-in function. I don't see an "onclick" event in the button widget. Any suggestions on how to do this?
function confirmationDialog(msg, confirmFunction)
{
var desc = app.pageFragments.ConfirmationDialog.descendants;
var label = desc.Label;
var confirmButton = desc.Confirm;
label.text = msg;
confirmButton.onClick = confirmFunction; // does not work
app.showDialog(app.pageFragments.ConfirmationDialog);
}
Thanks
It'd be great if this was a bit easier, but the best bet is to use Custom Properties (https://developers.google.com/appmaker/ui/viewfragments).
You can set up a custom property of type "Dynamic" and call it anything, take "onConfirmCallback", for example. Then you can set the function on that custom property:
Code to invoke dialog:
app.pageFragments.ConfirmationDialog.properties.onConfirmCallback = function(param) {
alert(param);
};
app.showDialog(app.pageFragments.ConfirmationDialog);
And then in the onClick for the close button:
app.pageFragments.ConfirmationDialog.properties.onConfirmCallback("hi");
app.closeDialog();
Also note that there are slightly better ways to set up labels than in your example, also using custom properties.
Create custom properties for any widget properties you want to customize, and then bind those custom properties (#properties.propertyName) to the widget property. For example you might have a confirmText property, with the confirm buttons text property boudn to #properties.confirmText.
Then when you invoke your dialog, you can just set those custom properties. Quick modification of your example code using properties for everything:
function confirmationDialog(msg, confirmFunction)
{
var properties = app.pageFragments.ConfirmationDialog.properties;
properties.text = msg;
properties.confirmCallback = confirmFunction;
app.showDialog(app.pageFragments.ConfirmationDialog);
}
For my confirmation dialogs, I just set the onclick of the OK button before I show the dialog (everything is in one place, which is easier for the dummy (me) who will have to maintain it in six months:
var dialog=app.pages.ConfirmationDialog;
dialog.descendants.message.text='Are you sure...?'
dialog.descendants.btnOk.getElement().onclick=function(){
//do something here
app.closeDialog();
});
};
app.showDialog(dialog);
}

How to keep a list from scrolling on dataProvider refresh/update/change?

I have a simple list and a background refresh protocol.
When the list is scrolled down, the refresh scrolls it back to the top. I want to stop this.
I have tried catching the COLLECTION_CHANGE event and
validateNow(); // try to get the component to reset to the new data
list.ensureIndexIsVisible(previousIndex); // actually, I search for the previous data id in the IList, but that's not important
This fails because the list resets itself after the change (in DataGroup.commitProperties).
I hate to use a Timer, ENTER_FRAME, or callLater(), but I cannot seem to figure out a way.
The only other alternatives I can see is sub-classing the List so it can catch the dataProviderChanged event the DataGroup in the skin is throwing.
Any ideas?
Actually MUCH better solution to this is to extend DataGroup. You need to override this.
All the solutions here create a flicker as the scrollbar gets resetted to 0 and the it's set back to the previous value. That looks wrong. This solution works without any flicker and the best of all, you just change DataGroup to FixedDataGroup in your code and it works, no other changes in code are needed ;).
Enjoy guys.
public class FixedDataGroup extends spark.components.DataGroup
{
private var _dataProviderChanged:Boolean;
private var _lastScrollPosition:Number = 0;
public function FixedDataGroup()
{
super();
}
override public function set dataProvider(value:IList):void
{
if ( this.dataProvider != null && value != this.dataProvider )
{
dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE, onDataProviderChanged);
}
super.dataProvider = value;
if ( value != null )
{
value.addEventListener(CollectionEvent.COLLECTION_CHANGE, onDataProviderChanged);
}
}
override protected function commitProperties():void
{
var lastScrollPosition:Number = _lastScrollPosition;
super.commitProperties();
if ( _dataProviderChanged )
{
verticalScrollPosition = lastScrollPosition;
}
}
private function onDataProviderChanged(e:CollectionEvent):void
{
_dataProviderChanged = true;
invalidateProperties();
}
override public function set verticalScrollPosition(value:Number):void
{
super.verticalScrollPosition = value;
_lastScrollPosition = value;
}
}
I ll try to explain my approach...If you are still unsure let me know and I ll give you the source code as well.
1) Create a variable to store the current scroll position of the viewport.
2) Add Event listener for Event.CHANGE and MouseEvent.MOUSE_WHEEL on the scroller and update the variable created in step 1 with the current scroll position;
3) Add a event listener on your viewport for FlexEvent.UpdateComplete and set the scroll position to the variable stored.
In a nutshell, what we are doing is to have the scroll position stored in variable every time user interacts with it and when our viewport is updated (due to dataprovider change) we just set the scroll position we have stored previously in the variable.
I have faced this problem before and solved it by using a data proxy pattern with a matcher. Write a matcher for your collection that supports your list by updating only changed objects and by updating only attributes for existing objects. The goal is to avoid creation of new objects when your data source refreshes.
When you have new data for the list (after a refresh), loop through your list of new data objects, copying attributes from these objects into the objects in the collection supporting your list. Typically you will match the objects based on id. Any objects in the new list that did not exist in the old one get added. Your scroll position will normally not change and any selections are usually kept.
Here is an example.
for each(newObject:Object in newArrayValues){
var found:Boolean = false;
for each(oldObject:Object in oldArrayValues){
if(oldObject.id == newObject.id){
found = true;
oldObject.myAttribute = newObject.myAttribute;
oldObject.myAttribute2 = newObject.myAttribute2;
}
}
if(!found){
oldArrayValues.addItem(newObject);
}
}
My solution for this problem was targeting a specific situation, but it has the advantage of being very simple so perhaps you can draw something that fits your needs from it. Since I don't know exactly what issue you're trying to solve I'll give you a description of mine:
I had a List that was progressively loading data from the server. When the user scrolled down and the next batch of items would be added to the dataprovider, the scrollposition would jump back to the start.
The solution for this was as simple as stopping the propagation of the COLLECTION_CHANGE event so that the List wouldn't catch it.
myDataProvider.addEventListener(
CollectionEvent.COLLECTION_CHANGE, preventRefresh
);
private function preventRefresh(event:CollectionEvent):void {
event.stopImmediatePropagation();
}
You have to know that this effectively prevents a redraw of the List component, hence any added items would not be shown. This was not an issue for me since the items would be added at the end of the List (outside the viewport) and when the user would scroll, the List would automatically be redrawn and the new items would be displayed. Perhaps in your situation you can force the redraw if need be.
When all items had been loaded I could then remove the event listener and return to the normal behavior of the List component.

Display jquery dialog on postback in ASP.NET after saving a new record

What I would like to do is have the user add a new record to the database and popup a JQuery dialog confirming that the new record was saved. I thought this would be a simple exercise. I have a gridview bound to a LINQDataSource to allow the user to view and edit existing records and a textbox and a button to add new codes.
In the head of the document, I have the following:
$('#dialog').dialog({
autoOpen: false,
width: 400,
buttons: {
"Ok": function () {
$(this).dialog("close");
}
}
});
and futher down in the markup I have:
<div id="dialog" title="New Code Added">
<p>"<asp:Literal runat="server" ID="LiteralNewCode"></asp:Literal>" was successfully added.</p>
</div>
So when the user enters a new description and it passes all the validation, it's added to the database and the gridview is rebound to display the new record.
protected void ButtonSave_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
CCRCode.Add( <long list of paramters> );
GridCode.DataBind();
IsNewCode = true;
NewDescription = <new description saved to database>;
}
}
Now, here's where (I thought) I'd set a boolean property to indicate that a new description had been added as well as the text of the new description. See below:
protected bool IsNewCode
{
get { return ViewState["IsNewCode"] != null ? (bool)ViewState["IsNewCode"] : false; }
set { ViewState["IsNewCode"] = value; }
}
private string NewDescription
{
get { return ViewState["NewDescription"] != null ? ViewState["NewDescription"].ToString() : string.Empty; }
set { ViewState["NewDescription"] = value; }
}
Here's where I loose my way. My guess is I want to add functionality to include code similar to:
$('#dialog').dialog('open');
I've added a registerscriptblock method in the page_load event but that didn't work. Any ideas? Or am I just going about this entirely wrong?
Thanks.
Not really get what you want to do. But, i use jquery alot with .NET in my projects. here is how i do, probably could give you a hint.
foo.aspx.cs
public String ScriptToRun = "$('#dialog').dialog('open');";
change the value of ScriptToRun in your C# code
foo.aspx
$(document).ready(function() {<%=ScriptToRun %>});
Remember that whatever you done in backend is going to generate HTML, Css& javascript to browser.
Two ways: one, write the javascript in your server-side code. Or, define a JS method to show the dialog (say named showDialog), and call it via:
Page.ClientScript.RegisterStartupScript(... "showDialog();" ..);
RegisterStartupScript puts the method call at the end, ensure your script is above it to work. You can also wrap it with document.ready call too, to ensure JQuery is properly loaded.
I think that the only think that you have miss is the creation of the dialog when the Dom is ready.
$(document).ready(function() {$('#dialog').dialog('open');});
I posted code in a different question for a custom "MessageBox" class I wrote:
ASP.NET Jquery C# MessageBox.Show dialog uh...issue
the code by default uses the javascript alert() function, but you can define your callback so that it calls your custom javascript method to display the messages.

Flex: Popup Window - Get [ok] or [cancel]

I've done a lot of C# programming with both Winforms and WPF. I'm working on a Flex/Air app now for cross platform support. But this is my first flex project, so I'm learning as I go.
I've got a window that I want to popup, that the user will fill out a form, then hit OK or CANCEL. I set it up the same way I would've in C#, but it doesn't work, and I can't really see a way to make it do what I want.
EDIT:
So I'm trying events now, the events just don't seem to be handled...
EDIT again:
Oh, It's because the popup manager seems to create a new instance of the Form object, rather than using the one I created already.
so in the showWindow method, I put in this code rather than the popup manager:
parent.addChild(this);
then I remove it when I close it. The only problem is, it doesn't disable the rest of the parent like the popup manager does. Any suggestions on that?
PARENT:
private function btnAdd_Clicked():void
{
var form:Form = new Form();
form.addEventListener(CloseEvent.CLOSE, onFormClosed, false, 0, true);
recipeForm.showWindow(this);
}
private function onFormClosed(e:CloseEvent):void
{
//none of these Alerts are ever shown. I also tried breakpoints in debug to try an follow the code, with no luck
Alert.show("Closed");
if(e.detail == Alert.OK)
{
Alert.show("OK");
}
else if(e.detail == Alert.CANCEL)
{
Alert.show("Cancel");
}
}
CHILD:
private function btnCancel_Clicked():void
{
okClicked = false;
closeWindow();
}
public function closeWindow():void
{
var e:CloseEvent = new CloseEvent(CloseEvent.CLOSE);
e.detail = okClicked ? Alert.OK : Alert.CANCEL;
dispatchEvent(e);
PopUpManager.removePopUp(this);
}
public function showWindow(parent:WindowedApplication):void
{
var window:IFlexDisplayObject = PopUpManager.createPopUp(parent, RecipeForm, true);
PopUpManager.centerPopUp(window);
}
You can do this at least two different ways:
FIRST WAY: Using events
Let your Form class dispatch an event when either of the buttons is clicked. After Form is instantiated from the parent view, add an eventListener for the event(s) it's known to dispatch. When the Form dispatches the event, the eventListener will be invoked. You can even reuse Flex's CloseEvent and set the "detail" property to either Alert.OK or Alert.CANCEL before dispatching it.
In Form:
var e:CloseEvent = new CloseEvent(CloseEvent.CLOSE);
e.detail = okClicked ? Alert.OK : Alert.CANCEL;
dispatchEvent(e);
In parent:
var f:Form = new Form();
f.addEventListener(CloseEvent.CLOSE, onClose, false, 0, true);
...
private function onClose(e:CloseEvent):void
{
if (e.detail == Alert.OK)
// do something
else if (e.detail == Alert.CANCEL)
// do something else
}
SECOND WAY: Using callbacks
Add a public var of type "Function" to your Form class and supply a callback function from the parent. This does basically the same thing as #1 except with little less abstraction / indirection.
I would recommend #1 since the event model in Flex is pretty well-conceived and more flexible than the callback.
In Form:
var e:CloseEvent = new CloseEvent(CloseEvent.CLOSE);
e.detail = okClicked ? Alert.OK : Alert.CANCEL;
dispatchEvent(e);
In parent:
var f:Form = new Form();
f.addEventListener(CloseEvent.CLOSE, onClose, false, 0, true);
...
private function onClose(e:CloseEvent):void
{
if (e.detail == Alert.OK)
// do something
else if (e.detail == Alert.CANCEL)
// do something else
}
Not sure if this is still an open issue. I ran into this very same problem and I think I figured out what is wrong. At least I did for my problem.
I implemented things exactly as you did. I also have the close attribute set to closeWindow (I'm using a TitleWindow for my dialog).
So when the window is closed via the X at the top, it will call closeWindow, also if you click on the Cancel button, it will also call closeWindow.
The problem for me was that clicking cancel, dispatches a CloseEvent which seems to be caught by a Listener which calls closeWindow again (possibly via the close attribute which probably creates its own internal listener). I'm not sure if its an infinite loop but Flex does not like this.
My solution was to create two functions, one for the X close window to call and one for the Cancel button to dispatch a CloseEvent of its own. This seemed to work for me. Hope it helps you.

Events Overwritten in ASP.AJAX on IE7

Greetings!
I'm calling a Web service from Javascript when a user clicks on a link. I need to get the coordinates where the user clicked so that I can display a DIV in an appropriate location. My client-side script looks like the following:
var g_event;
function DoWork(event, theId)
{
if (IsIE())
g_event = window.event;
else
g_event = event;
Acme.WebServices.Worker.GetInformation(theId, DoWorkSuccess);
}
function DoWorkSuccess(result)
{
var l_elemDiv = document.getElementById("content-area-div");
DisplayAreaDiv(g_event, l_elemDiv, result);
}
It's used like this:
Help
This works great in Firefox, Safari, and Opera. In IE7, not so much. For example, if I place the following code at the end of both the DoWork() and DoWorkSuccess() functions:
alert(g_event.clientX + ", " + g_event.clientY);
In IE, I'll get two alerts; the first one has correct coordinates, but the second one (which displays on top of the first one) is simply "[object]". Since that "[object]" one is the last one, my DIV is incorrectly displayed in the top left of the browser window. Is there a way I can prevent IE from giving me a second "bad" event? Thanks.
Why not extract and save the coordinates in DoWork and simply use them in DoWorkSuccess rather than saving the event. Of course this won't work if there is more data you are extracting from the event.
var client_x;
var client_y;
function DoWork(event, theId)
{
var g_event;
if (IsIE())
g_event = window.event;
else
g_event = event;
client_x = g_event.clientX;
client_y = g_event.clientY;
Acme.WebServices.Worker.GetInformation(theId, DoWorkSuccess);
}
function DoWorkSuccess(result)
{
var l_elemDiv = document.getElementById("content-area-div");
DisplayAreaDiv( { clientX : client_x, clientY : client_y }, l_elemDiv, result);
}
Have you tried setting window.event.cancelBubble = true in your DoWork function?
If not, quirks mode has good article on events and event bubbling - http://www.quirksmode.org/js/events_order.html that has helped me a lot with these kinds of issues.

Resources