I have been trying to get the scroll position of a tree grid in and ext.js application using sencha architect. Originally I wanted to keep the scroll position after a reload so when a user deletes a post it will scroll back to that same spot after reload. I have attempted to use various methods I have searched for but nothing is working. I'm currently testing by having a java script timeout function give me the scroll position after a few seconds, long enough for me to scroll down and console.log the position but it gives me nothing and I'm not showing anything but zero when I go into the dom and look at the tree view object. I have already tried the following
1st: var newcompheight = comboboxeample.getHeight();
2nd: getScroll: function() {
var me = this,
dom = me.dom,
doc = document,
body = doc.body,
docElement = doc.documentElement,
left, top;
if (dom === doc || dom === body) {
// the scrollLeft/scrollTop may be either on the body or documentElement,
// depending on browser. It is possible to use window.pageXOffset/pageYOffset
// in most modern browsers but this complicates things when in rtl mode because
// pageXOffset does not always behave the same as scrollLeft when direction is
// rtl. (e.g. pageXOffset can be an offset from the right, while scrollLeft
// is offset from the left, one can be positive and the other negative, etc.)
// To avoid adding an extra layer of feature detection in rtl mode to deal with
// these differences, it's best just to always use scrollLeft/scrollTop
left = docElement.scrollLeft || (body ? body.scrollLeft : 0);
top = docElement.scrollTop || (body ? body.scrollTop : 0);
} else {
left = dom.scrollLeft;
top = dom.scrollTop;
}
return {
left: left,
top: top
};
3rd: var test = window.pageYOffset;
I have also attempted to setting the keepscroll position property in Sencha architect to true and other things I have googled but nothing is working. Any help would be appreciated.
Use this:
treeGrid.getEl().getScrollTop()
Related
I am trying to use ui-scroll to provide dynamic scrolling through a large dataset.
The get method calls a back end function which queries a database. The query is "slow" so I'd like to disable queries while the scroll thumb is moving.
For example, suppose the viewport shows 10 rows and there are 100,000 rows in the database and we fetch 100 rows at a time.
If you quickly drag the thumb from the top to the bottom, ui-scroll currently makes lots and lots of requests for data. I'd like to skip all of the intermediate requests and only fetch data when the thumb stops moving.
I've fiddled with isLoading on the adapter but couldn't find a way to make this work.
Suggestions? Angular 1.4.1.
$scope.datasource = { };
$scope.datasource.get = fetchData
$scope.datasource.minIndex = 0;
$scope.datasource.maxIndex = 10553;
$scope.scrollAdaptor = {};
var loadCount = 0;
function fetchData(desc, successCb)
{
var start = desc.index;
var end = desc.index + desc.count - 1;
var url = "scrollTest.php?start=" + start + "&end=" + end;
$http.get(url)
.then(function(goodResp)
{
console.log("got data, loadCount", loadCount);
successCb(goodResp.data);
},
function(badResp)
{
});
};
There is a discussion on GitHub related to the question. In short, angular-ui-scroll can't skip intermediate requests out-of-box, but following workaround might help.
Set min/max indexes on start to make the viewport relevant to
100,000 rows
$scope.datasource.minIndex = 1
$scope.datasource.maxIndex = 10000
Bind additional scroll event to intercept user scrolling over the viewport
Check scroll position delta between two events, and if it is more than some fixed value (say, 500px), rebuild the viewport
Rebuild means adapter.reload(indexToReload) method call and setting min/max indexes
The last thing is indexToReload, it should be calculated by current scroll position and item height:
indexToReload = Math.floor(scrollTop/itemHeight)
I'm looking for a way to change the value (or format) for an individual series label when hovering it in anycharts.
Currently I'm only able to access the entire axis and I can find no getter method for individual labels so as to attach a listener.
xAxis.labels().listen('mouseOver', function(e) {
console.log(this, e.target);
});
This jsfiddle is as far as I got (see console log), this as well as the event.target reference the entire axis but not the label:
https://jsfiddle.net/robstarbuck/pbhd4b7L/9/
Indeed, there was a little bug with cache and format() function, our dev team made the fix, so please check the working sample:
var labelIndex = e.labelIndex;
var label = this.getLabel(labelIndex);
var value = xAxis.scale().ticks().get()[labelIndex];
label.format(value * 2);
https://jsfiddle.net/pbhd4b7L/13/ – it also shows how to work with tick values:
Currently it takes the js from branch, but this fix will be included in the upcoming release – 7.14.0 version (ETA: May 2017)
Our API is a little bit complicated here, but we're working hard to improve it. Does this what you're looking for?
var labelIndex = e.labelIndex;
var label = this.getLabel(labelIndex);
label.fontColor('red');
label.draw();
https://jsfiddle.net/pbhd4b7L/10/
This issue was fixed in the 7.14.0 release, use this code:
xAxis.labels().listen('mouseOver', function(e) {
var labelIndex = e.labelIndex;
var label = this.getLabel(labelIndex);
var value = xAxis.scale().ticks().get()[labelIndex];
label.format(value * 2);
label.fontColor('red');
label.draw();
});
with the latest version: https://jsfiddle.net/2t08ahkg/3/
I'm using AngularJS 1.5.0 and Microsoft Edge browser screen doesn't reflect the DOM.
I would like some suggestion how this can be fixed.
I can't really apply a fix for each element as the application is somewhat big with dynamic user content including Angular equations.
Also the app include a lot of dynamic bindings linked to input boxes.
Selecting the text with the mouse turn the 0 into a 2 which is the right value in the example below.
Also changing the position style back and forth seem to force Edge to redraw the element but it's somewhat an ugly fix that I don't like very much and it need to be trigger at so many places (Ajax request, input changes and so on...)
The page start with a value of 0. Then an Ajax call is made and it go fetch the real data. After some experimentation the bug only appears if the new data is 1 character (ex: 2 or 9). And it happens every time. If it's a 2 digit number (ex: 26) then the good number appears.
Any help on this matter would be gladly appreciated.
We were facing the same problem and it stopped occurring after removing the text-transform: uppercase style from the elements that are not updating.
#Sampson, it looks like this is a bug in Edge.
I was able to make a temporary fix with the use of Mutation Observer.
Little script that I made that works for AngularJS elements created server side.
Currently those are the only one causing trouble in my app.
<script>
$(document).ready(function(){
var ua = navigator.userAgent;
var re = new RegExp("Edge/");
if (re.exec(ua) != null){
console.log('edgeMutationObserver ON!!')
var edgeMutationConfig = { characterData: true, subtree: true };
var edgeMutationObserver = new MutationObserver(function(mutations) {
var rgb_p = /rgb\((\d+), (\d+), (\d+)\)/g;
var rgba_p = /rgba\((\d+), (\d+), (\d+), (\d.?\d*)\)/g;
mutations.forEach(function(mutation){
if(mutation.target.nodeType == 3){
var that = mutation.target.parentNode;
// Save the background color
var bgc = that.style.backgroundColor;
// Get applied style from style or css
var bgc_css = bgc || $(that).css('backgroundColor');
var bgc_temp,match;
if(match = rgb_p.exec(bgc_css)){
// rgb transformed in rgba triggers update
bgc_temp = 'rgba('+match[1]+','+match[2]+','+match[3]+',1)';
}else if(match = rgba_p.exec(bgc_css)){
// Slightly modify transparency
var alpha = match[4] == 0 ? 0.01 : match[4] - 0.01 ;
bgc_temp = 'rgba('+match[1]+','+match[2]+','+match[3]+','+alpha+')';
}else{
// If either inline style or css is already equal to transparent the redraw is not made so i choose an alternate color with 0 opacity
bgc_temp = bgc_css != 'transparent' ? 'transparent' : 'rgba(0,0,0,0)';
}
// Change background color to force redraw
that.style.backgroundColor = bgc_temp;
setTimeout(function(){
// Apply back previous style
// Doesn't redraw without a timeout in Edge
that.style.backgroundColor = bgc;
},0);
}
});
});
$('.ng-binding').each(function(){
edgeMutationObserver.observe(this, edgeMutationConfig);
});
}
});
</script>
I'm building an app where the first view has a menu panel, and I want this panel to stick around for the life of the app. The only places the user can "go" are reachable via buttons on this panel (a UICollectionView). In case it matters, this app is landscape-only, and iOS 6-only.
In order to make this work I created a custom segue, which removes everything from the view except for the menu panel, then adds the new view controller's view as a subview, sets the new view's frame to the bounds of the superview, and sends the new view to the back (so it's behind the menu panel). I call viewWill/DidDisappear from prepareForSegue, because otherwise they don't get called.
It may sound kludgy (it does to me), but it works fine except for one thing - the new view comes up from the bottom. It looks funny.
I then tried adding my own animation block - I initially locate the view off to the left, then animate it into place. I send it to the back in the completion block for the animation. This seems perfectly logical, and the frame values are all what they should be. But this one is worse - the view comes in from the lower left corner.
Can anyone suggest a way to make this work? Here's my current perform method:
- (void)perform {
MainMenuViewController *sourceVC = (MainMenuViewController *)self.sourceViewController;
UIViewController *destinationVC = (UIViewController *)self.destinationViewController;
for (UIView *subview in [sourceVC.mainView subviews]) {
// don't remove the menu panel or the tab
if (![subview isKindOfClass:[UICollectionView class]] && [subview.gestureRecognizers count] == 0) {
[subview removeFromSuperview];
}
}
[sourceVC.mainView addSubview:destinationVC.view];
CGRect finalFrame = sourceVC.mainView.bounds;
CGRect frame = finalFrame;
frame.origin.x = finalFrame.origin.x - finalFrame.size.width;
destinationVC.view.frame = frame;
[UIView animateWithDuration:0.5 animations:^{
destinationVC.view.frame = finalFrame;
} completion:^(BOOL finished) {
// make sure it ends up behind the main menu panel
[sourceVC.mainView sendSubviewToBack:destinationVC.view];
}];
}
It turned out to be a simple error - I needed to set destinationVC's frame before calling addSubview. Setting it afterwards was triggering the unwanted animation.
I am creating an item selector with two boxes that move things back and forth within an extjs application. On the right box, I am creating buttons that serve to move items up and down. Essentially I am swapping the item with one above or below it. So, my code is straight forward in that regard
MoveUp: function(button, event, eOpts){
var theChosen = Ext.getStore('storeId').getRootNode().findChild('text', 'Chosen folder');
var chosenPanel = Ext.ComponenetQuery.query('#chosenTreePanel')[0];
var selected = chosenPanel.getSelectionModel().getSelection();
for( var i = 1; i < theChosen.childNodes.length; i++){
if(Ext.Array.contains(selected, theChosen.childNodes[i]) && (!Ext.Array.contains(selected, theChosen.childNodes[i-1]){
var temp = theChosen.childNodes[i];
theChosen.childNodes[i] = theChosen.childNodes[i-1];
theChosen.childNodes[i-1] = temp;
}
}
}
All of this code seems to work fine, because after clicking my button, and checking the DOM in firebug, I can see that the selected nodes have moved in the array correctly, however, this effect is never shown within my treepanel. ???How do I make the treepanel update when it's elements change. ???
TreePanel heirarchy looks like this just to clarify
Root Node
'Chosen Folder Node'
Array of items I am moving up and down within the 'folder'
I am USING VERSION 4.0.7
Attempting to use replaceChild() to fire an event to rerender does not behave as I expected
Changing:
var temp = theChosen.childNodes[i];
theChosen.childNodes[i] = theChosen.childNodes[i-1];
theChosen.childNodes[i-1] = temp;
To:
var temp = theChosen.childNodes[i];
theChosen.replaceChild(theChosen.childNodes[i-1], theChosen.childNodes[i]);
theChosen.replaceChild(temp, theChosen.childNodes[i-1]);
Results in odd behavior in which some nodes go missing. Certaintly not what I was looking for. Where am I going wrong here?
Tried the following code using the datachanged and (undocumented)refresh event:
Ext.getStore('storeId').fireEvent('datachanged', Ext.getStore('chosen') );
Ext.getStore('storeId').fireEvent('datachanged', Ext.getStore('chosen') );
This does not reload anything...
SOLUTION:
Use the insertChild method of nodeInterface....
I have noticed something strange in how insertChild works in that I need to change my index more based on moving up or down will explain with code below.
To move Up:
theChosen.insertChild( (i-1), theChosen.childNodes[i]);
To move down:
theChosen.insertChild( (i+2), theChosen.childNodes[i]);
Although the -1 vs +2 they both effectively move the item by one in the appropriate direction.
If you want to update the view of the nodes, I recommend using yourTree.getView().refresh();
But you can avoid that by using parentNode.insertChild(index, childNode); where index is where you want the node to show up and parentNode is the parent to the nodes you are reordering. ChildNode can be a config for a new node or any other nodeinterface that already exists. If the node does already exist and you use the insertChild method to insert it, it will automatically remove that node from whereever else it is.
So as you provided in your question in response to my answer, your code will work with something like (this is probably how I'd do it, but this is untested):
MoveUp: function(button, event, eOpts){
var chosenPanel = Ext.ComponenetQuery.query('#chosenTreePanel')[0];
var selectedNodes = chosenPanel.getSelectionModel().getSelection();
for( var i = 0; i < selectedNodes.length; i++){
var currentNode = selectedNodes[i];
if(!currentNode.isFirst())
{
var parentNode = currentNode.parentNode;
var newIndex = parentNode.indexOf(currentNode) - 1;
parentNode.insertChild(newIndex, currentNode);
}
}
}
Edit:
Back to the the responsible event question...
You need to fire the
'datachanged'
'refresh'
Events on the store with the store as only param. That should cause a UI update. But please note that I just had a glimpse into the sourcecode and I am sure this can all be done much smarter. At least a DD solution for this exists already.
If I find some time I my look into this again, but I guess you should be fine with these events for the first.
You never see anything cause you just do it without the appropriate methods that then fire the responsible events that cause rerender. Take a look at
appendChild()
removeChild()
replaceChild()
There may also be more methods that can help on the Ext.data.NodeInterface. I recommend you to use these instead of doing it under hood without any responsible event fired.
In addition to my second comment (just a wild guess without knowing if that is exactly what you want):
MoveUp: function(button, event, eOpts){
var target = Ext.getStore('storeId').getRootNode().findChild('text', 'Chosen folder');
var selected = chosenPanel.getSelectionModel().getSelection();
target.appendChild(selected);
}