$ionicScrollDelegate locks the view on the scrolled value - angularjs

When I'm getting the list of results in my cordova app, i want to roll it to the specified element with this function:
$scope.roll = function () {
//var rankScroll = $ionicScrollDelegate.$getByHandle('rank');
var meElement = document.getElementById('scroll');
if (!meElement) {
$ionicScrollDelegate.scrollTo(0, 0);
return;
}
var top = meElement.getBoundingClientRect().top - 50;
$ionicScrollDelegate.scrollTo(0, top);
console.log(top);
console.log($ionicScrollDelegate.getScrollView());
}
It works nicely, but I can't scroll to any other place in the list. I want to unlock scrolling in this solution or find better one. It should scroll on page loaded, not on click.
All the best

That function lock your scroll because of the $scope's binding.
If you only want that function to be invoked when the view is loaded, you should call it once at the the time the view is loaded.
You can do that by this way in your controller:
var roll = function () {
//var rankScroll = $ionicScrollDelegate.$getByHandle('rank');
var meElement = document.getElementById('scroll');
if (!meElement) {
$ionicScrollDelegate.scrollTo(0, 0);
return;
}
var top = meElement.getBoundingClientRect().top - 50;
$ionicScrollDelegate.scrollTo(0, top);
console.log(top);
console.log($ionicScrollDelegate.getScrollView());
}
$scope.$on("$ionicView.loaded", function (scopes, states) {
roll();
});
You can check more $ionicView events in this ion-view Document

Related

How can I set up the browser size before my protractor test runs?

I have the following protractor test listed below. It runs fine. But I need to add some code that opens the browser to full screen since my test is sensitive to pixel location of gridster tiles. How can this be done?
describe('DragAndDrop Test', function () {
require('protractor');
require('jasmine-expect');
beforeAll(function () {
context = new Context();
context.get();
browser.waitForAngular();
browser.driver.manage().window().maximize();
});
it('should drag and drop Application Experience tile', function () {
//a = angular.element(document).find('h3')[1]
//target is where we are dragging the box to. Box is the Box
var target = { x: 300, y: 50 };
var box = element(by.cssContainingText('h3', 'Application Experience'));
var infoSpot = element(by.cssContainingText('h3', 'Application Experience'));
//scope is going to hold the scope variables that tell us where the box is located
//get the standardItems Scope
box.evaluate('dashboards').then(function(scope) {
//make sure the box we are using is initially set in column 0 and Row 0
expect(scope['1'].widgets[0].col).toEqual(0);
expect(scope['1'].widgets[0].row).toEqual(0);
});
//drag and drop the box somewhere else.
browser.actions().dragAndDrop(box, target).perform();
browser.waitForAngular();
browser.driver.sleep(5000);
//get the updated scope
box.evaluate('dashboards').then(function(scope) {
//test to see that the box was actually moved to column 1 and row 0
expect(scope['1'].widgets[0].col).toEqual(1);
expect(scope['1'].widgets[0].row).toEqual(0);
});
});
});
var Context = function () {
this.ignoreSynchronization = true;
//load the website
this.get = function () {
browser.get('http://127.0.0.1:57828/index.html#/dashboard');
};
};
I think the better practice is to do this in your config.
onPrepare: function() {
browser.manage().window().setSize(1600, 1000);
}
or
onPrepare: function() {
browser.manage().window().maximize();
}
You already have this line in your beforeAll function, which will maximize your browser before any test is run:
browser.driver.manage().window().maximize();
However, on some operating systems, Chrome browser won't maximize the window horizontally, only vertically. You have two options:
a) Set the width explicitly to some predefined value, e.g:
browser.driver.manage().window().setSize(1200, 768);
b) Get the screen resolution with a Javascript function and set the window size accordingly.
var width = GET_WIDTH;
var height = GET_HEIGHT;
browser.driver.manage().window().setSize(width, height);

Create and destroy Angular watchers

I would like to turn off this watcher because it keeps hitting "kendoWidgetCreated" event over and over again, and causes an infinite loop where I hit the kendoGrid.refresh() .
How can I turn it off, then turn back on ?
scope.$on("kendoWidgetCreated", function (ev, widget) {
var kendoGrid = widget.element.parent().find('.k-grid').data("kendoGrid");
if (kendoGrid != undefined) {
kendoGrid.$angular_scope.compileTemplate();
kendoGrid.refresh();
}
});
I tried something like this, but couldn't get the watcher to trigger :
var kendoWidgetWatcher = scope.$watch("kendoWidgetCreated", refreshKendoWidgets);
var refreshKendoWidgets = function (ev, widget) {
// widget compile/refresh code here...
}
Advice is always appreciated...
regards,
Bob
***** UPDATE ****
My initial idea for creating an anonymous function was NOT working; however, Pankar's answer below worked for me.
Here's the updated, working version :
// setup new 'kendoWidgetWatcher' object for Kendo widget watcher, compile/refresh Kendo grids/charts
var kendoWidgetWatcher;
function registerWatcher() {
kendoWidgetWatcher = scope.$on("kendoWidgetCreated", refreshKendoWidgets);
}
function refreshKendoWidgets(ev, widget) {
var ht = widget.getSize().height;
var wt = widget.getSize().width;
var kendoGrid = widget.element.parent().find('.k-grid').data("kendoGrid");
if (kendoGrid != undefined) {
if (kendoWidgetWatcher) {
kendoWidgetWatcher(); // disable watch
}
kendoGrid.$angular_scope.compileTemplate(); // recompile the html tempate, then refresh kendo widget
kendoGrid.refresh();
registerWatcher(); // re-enable
}
}
You could easily turn off your your watcher by calling the watcher reference as function, and re-register it whenever you want it.
var kendoWidgetWatcher;
function refreshKendoWidgets(ev, widget) {
var kendoGrid = widget.element.parent().find('.k-grid').data("kendoGrid");
if (kendoGrid != undefined) {
kendoGrid.$angular_scope.compileTemplate();
kendoGrid.refresh();
// HOW TO DISABLE THE WATCH HERE ?
}
}
function registerWatcher (){
kendoWidgetWatcher = scope.$watch("kendoWidgetCreated", refreshKendoWidgets);
}
registerWatcher();
//you could call below code for re-registering the watcher
if(kendoWidgetWatcher)
kendoWidgetWatcher(); //to deregister it.
registerWatcher(); //re-register it.

$compile an HTML template and perform a printing operation only after $compile is completed

In a directive link function, I want to add to document's DIV a compiled ad-hoc template and then print the window. I try the following code and printer preview appears, but the data in preview is still not compiled.
// create a div
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
// Trying to add some template to div
scope.someVar = "This is print header";
var htmlTemplate = "<h1>{{someVar}}</h1>";
var ps = angular.element(printSection);
ps.append(htmlTemplate);
$compile(ps.contents())(scope);
// What I must do to turn information inside printSection into compiled result
// (I need later to have a table rendered using ng-repeat?)
window.print();
// ... currently shows page with "{{someVar}}", not "This is print header"
Is it also so that $compile is not synchronous? How I can trigger window.print() only after it finished compilation?
you just need to finish the current digestion process to be able to print
so changing
window.print();
to
_.defer(function() {
window.print();
});
or $timeout, or any deferred handler.
will do the trick.
The other way (probably the 'right' approach) is to force the newly compilated content's watchers to execute before exiting the current $apply phase :
module.factory("scopeUtils", function($parse) {
var scopeUtils = {
/**
* Apply watchers of given scope even if a digest progress is already in process on another level.
* This will only do a one-time cycle of watchers, without cascade digest.
*
* Please note that this is (almost) a hack, behaviour may be hazardous so please use with caution.
*
* #param {Scope} scope : scope to apply watchers from.
*/
applyWatchers : function(scope) {
scopeUtils.traverseScopeTree(scope, function(scope) {
var watchers = scope.$$watchers;
if(!watchers) {
return;
}
var watcher;
for(var i=0; i<watchers.length; i++) {
watcher = watchers[i];
var value = watcher.get(scope);
watcher.fn(value, value, scope);
}
});
},
traverseScopeTree : function(parentScope, traverseFn) {
var next,
current = parentScope,
target = parentScope;
do {
traverseFn(current);
if (!(next = (current.$$childHead ||
(current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
} while((current = next));
}
};
return scopeUtils;
});
use like this :
scopeUtils.applyWatchers(myFreshlyAddedContentScope);

Scrolling to an HTML Element in a Scrollable DIV from an AngularJS Controller

I am hoping that someone has seen this issue before and that you may have a solution.
I have a function that is called when my controller loads that should scroll an HTML element (happens to be a div element) to the top of a containing div that is scrollable. The HTML for the page is in a view that is loaded when the user navigates to the route associated with it, and the div to be scrolled to is created in an ng-repeat.
The scroll function works perfectly when called from a click function in a user interaction with the page after the controller and the view are loaded. The function is:
// scrolls the specified html element into view
function scrollToElementByID(id) {
// locate the html element to scroll to
var
elem = document.getElementById(question.divID);
// found the element associated with the question - set focus on it
if (elem) {
// get the position of the top of the element
var
topPos = elem.offsetTop;
// get the div in which the element is located
var
elemParent = elem.parentNode;
// scroll the containing div to the element position
elemParent.scrollTop = topPos;
}
}
However, the function does not work when first called from an initialization function that is called when the controller first loads. The getElementById function call returns null, which seems like it is indicating that the html element has not been created at the time of the call.
I have tried using the $viewContentLoaded event, but that fires long before the scroll call and it still fails, and setting a $timeout and an $interval did not work either. Anybody have a suggestion as to how I can scroll my scrollable div to a specified element when the user navigates to the route?
Thanks!
Further info based on Fedaykin's comment:
I modified your controller code to try to demonstrate what I need. Your sample directive works well when the user interacts with the page after it is loaded, as in your plunkr, but I need the scroll to occur automatically like this (see the comments marked CHANGE):
app.controller( 'myCtrl', [ '$scope', '$routeParams', function ( $scope, $routeParams ){
$scope.value = 'test';
$scope.itemsOne = [];
$scope.itemsTwo = [];
for(var i=0; i<10; i++){
$scope.itemsOne.push(makeSentence());
$scope.itemsTwo.push(makeSentence());
}
// CHANGE: get the row and column from query string params
var
row = $routeParams.r,
col = $routeParams.c;
// CHANGE: controller initialization function - called when controller loads
function init() {
// scroll to requested row in requested column
$scope.scrollToMe(row, col);
}
// CHANGE: call controller initialization
init();
function makeSentence() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < Math.random() * 200; i++ ){
for( var i=0; i < Math.random() * possible.length; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
text += " ";
}
//console.log(text);
return text;
}
$scope.scrollMeTo = function(column, row){
// scroll me to an area in a column
if(column == 1)
$scope.itemColumn1 = row;
if(column == 2)
$scope.itemColumn2 = row;
};
}] );
Thanks for the help!

mobiscroll image list with .click() handler

When I bind a
$(document).on("click", '.dw-sel', function(e) { opens modal box });
on click, it fires each time, even when there is a drag. I want to get the click function called, only when there is a click without any draging of the wheel. Is there any of such event provided already? Or how to achieve differenciating click from drag?
EDIT:
ok, found a solution line 929 in mobiscroll.core.js
if (!dist && !moved) { // this is a "tap"
istap = true;
tindex = Math.floor((stop - ttop) / h);
var li = $('.dw-li', target).eq(tindex)
li.addClass('dw-hl'); // Highlight
setTimeout(function() {
li.removeClass('dw-hl');
}, 200);
} else {
tindex = Math.round(pos - dist / h);
istap = false;
}
I set the variable istap, and on that I based my click event.

Resources