Angular NgStyle background image isn't refreshing - angularjs

I am trying to change the background image based on window resize. I am getting the correct output in console in terms of the image path that I need. But for some reason the url just doesn't update in the div.
This is in a directive:
angular.element($window).on('resize', function(){
waitForFinalEvent(function(){
checkSize();
}, 500);
});
$scope.index = 0;
var checkSize = function(){
var width = angular.element($window).width();
var height = angular.element($window).height()
console.log('w: ' +width);
console.log('h: '+height);
$scope.index ++;
if(width < 1050 && width > 800 ) {
$scope.slideImage = $scope.displaySlideImageM;
console.log('here1: ' +$scope.slideImage);
} else if(width < 799 && height < 800) {
$scope.slideImage = $scope.displaySlideImageM;
console.log('here2: ' +$scope.slideImage);
} else if(width < 799 && height > 800) {
$scope.slideImage = $scope.displaySlideImageP;
console.log('here3: ' +$scope.slideImage);
} else {
$scope.slideImage = $scope.displaySlideImageO;
console.log('here4: ' +$scope.slideImage);
}
}
var waitForFinalEvent = (function () {
var timers = {};
return function (callback, ms) {
if (timers) {
clearTimeout(timers);
}
timers = setTimeout(callback, ms);
};
})();
html:
<div class="result-slide" ng-style="{'background-image':'url('+ slideImage +'?v='+ index +')'}"></div>
As you can see I tried adding a random param to the end of the url with ?v=n to attempt to trigger the refresh. But although the index changes, the physical slideImage url isn't updating.
Can someone please shed some light to this issue?

A quick scan of your code shows that you should be using $timeout, instead of setTimeout. While both things execute the timer fine, setTimeout occurs outside of angular so the $scope assignments will not be updated. If you do use setTimeout, then you need to wrap your assignment code in $scope.apply().
You can read about it more here. https://docs.angularjs.org/api/ng/service/$timeout

Related

Line Chart not updating everytime

So I am using Line from react-chartjs-2 and I've added an onClick event to the labels which blur all the lines except the current one.
Here is my onClick function code:
legend:{
'onClick': function(e, legendItem) {
var index = legendItem.datasetIndex;
var ci = this.chart;
console.log(ci.data.datasets);
//var alreadyHidden = (ci.data.datasets[index].borderColor === ci.data.datasets[index].accentFadedColor) ? false : true;
for(var i=0; i< ci.data.datasets.length;i++){
if (i !== index) {
ci.data.datasets[i].borderColor = ci.data.datasets[i].accentFadedColor;
} else if (i == index){
ci.data.datasets[i].borderColor = ci.data.datasets[i].accentColor;
}
}
that.updateValue(index);
ci.update();
}
The problem is, the function updates the chart on first click but not after that. Though I can see the updates values with console.log()
Any idea what I am doing wrong?
Update:
So apparently my chart is working fine. Inside the onClick() I'm making call to another function ( which sets state ) which is causing this behavior.
Here's a link to stackblitz
Any advice?
So apparently, just making the function call inside onClick() but before updating the datasets solved the problem.
I think rendering after setState and canvas update were somehow mixing up.
Here's the updated code:
legend:{
'onClick': function(e, legendItem) {
var index = legendItem.datasetIndex;
var ci = this.chart;
that.updateValue(index);
for(var i=0; i< ci.data.datasets.length;i++){
if (i !== index) {
ci.data.datasets[i].borderColor = ci.data.datasets[i].accentFadedColor;
ci.data.datasets[i].lineWidth = ci.data.datasets[i].highlightedWidth;
} else if (i == index){
ci.data.datasets[i].borderColor = ci.data.datasets[i].accentColor;
ci.data.datasets[i].lineWidth = ci.data.datasets[i].fadedWidth;
}
}
ci.update(); }

AngularJS/ionic: Navigating specific screen items via direction keys

I am trying to implement a mechanism where specific items on a screen are navigable using arrows keys.
At the moment, I am drawing a red box around items as they move and pressing enter activates them.
I have the following directive:
(credits here and here)
.directive("moveNext", function() {
return {
restrict: "A",
link: function($scope, element,attrs) {
element.bind("keyup", function(e) {
if (e.which == 37) {
console.log ("MOVE LEFT:" + JSON.stringify(element));
element[0].classList.remove('selected');
var partsId = attrs.id.match(/move-(\d+)/);
console.log ("CURRENT PARTS="+JSON.stringify(partsId));
var currentId = parseInt(partsId[1]);
console.log ("Looking for move-"+(currentId-1));
var nextElement = angular.element(document.querySelectorAll('#move-' + (currentId - 1)));
// var $nextElement = element.next().find('movehere');
if(nextElement.length) {
nextElement[0].classList.add('selected');
nextElement[0].focus();
// $nextElement[0].style.border='5px solid red';;
}
}
if (e.which == 39) {
console.log ("MOVE RIGHT:" + JSON.stringify(element));
element[0].classList.remove('selected');
var partsId = attrs.id.match(/move-(\d+)/);
var currentId = parseInt(partsId[1]);
console.log ("CURRENT PARTS="+JSON.stringify(partsId));
var currentId = parseInt(partsId[1]);
var nextElement = angular.element(document.querySelectorAll('#move-' + (currentId + 1)));
console.log ("Looking for move-"+(currentId+1));
// var $nextElement = element.next().find('movehere');
if(nextElement.length) {
nextElement[0].classList.add('selected');
nextElement[0].focus();
// $nextElement[0].style.border='5px solid red';;
}
}
if (e.which == 13) {
console.log ("ENTER:" + JSON.stringify(element));
// element.triggerHandler('click');
}
});
if (event) event.preventDefault();
}
}
})
And then in the template I have the following, for example:
<div>
<button move-next id="move-1" ng-click="d1()">Yes</button>
<button move-next id="move-3" ng-click="d1()">Yes</button>
<button ng-click="d1()">No</button>
<button move-next id="move-2" ng-click="d1()">Yes</button>
</div>
Yes <!-- PROBLEM -->
Yes <!-- NEVER COMES HERE -->
The nice part is I can now navigate to any "clickable" element depending on the ID order I set, which is my intention. The problem is that focus() only works on items that are focusable, so once "move-4" is highlighted by the directive, the focus() doesn't really work so I can never move "next" to "move-5"
thanks
Problem solved:
I removed the directive, and instead wrote a global keyUpHandler
Inside the keyup handler, I kept state on last selected item ID, so I could +- it irrespective of whether an item is focusable or not.
I can now navigate arbitrary items on any view with direction pad.
The problem however is that move-Ids must be unique across views or I need to find a way to do a query only on the active view. I need to figure out how to do that. currentView = document.querySelector('ion-view[nav-view="active"]'); doesn't work.
The code (needs cleanup, but seems to work)
window.addEventListener('keyup', keyUpHandler, true);
function keyUpHandler(evt){
$timeout (function() {
var currentView = document.querySelector('ion-view[nav-view="active"]');
var keyCode=evt.keyCode;
var el, nextel;
if (keyCode == 13 ) {
if ($rootScope.dpadId >0) {
el = angular.element(currentView.querySelector('#move-' +$rootScope.dpadId));
el.triggerHandler('click');
}
return;
}
if (keyCode == 37 || keyCode == 39) {
if ($rootScope.dpadId < 1) {
console.log ("First dpad usage");
$rootScope.dpadId = 1;
el = angular.element(currentView.querySelector('#move-1'));
if (el.length) {
el[0].classList.add('selected');
}
} else {
// unselect old
el = angular.element(currentView.querySelector('#move-' +$rootScope.dpadId));
var nextId = (keyCode == 37) ? $rootScope.dpadId -1: $rootScope.dpadId + 1;
nextel = angular.element(currentView.querySelector('#move-' +nextId));
if (nextel.length) {
el[0].classList.remove('selected');
nextel[0].classList.add('selected');
$rootScope.dpadId = nextId;
}
console.log ("dpadID="+$rootScope.dpadId);
}
}
});
}

UI Grid showing only last record many times on infinite scroll

Before Scrolling
After Scrolling
In Grid on first time load I am getting data properly.
After scrolling down it is getting problem.
It displays last record from the first load's last record in every row.
Below is my code for infinite scroll function.
$scope.getDataDown = function() {
var promise = $q.defer();
$scope.lastPage++;
if ($scope.data.length < $scope.total) {
$http(getRequest()).success(function(data) {
promise.resolve();
var jb = JSON.stringify(data.content);
$scope.gridApi.infiniteScroll.saveScrollPercentage();
$scope.data = $scope.data.concat(data.content);
$scope.total = data.total ? data.total : data.length;
$scope.length = $scope.data.length;
$scope.gridApi.infiniteScroll.dataLoaded(false,
$scope.lastPage < ($scope.total / $scope.pageSize));
}).error(function(error) {
$scope.gridApi.infiniteScroll.dataLoaded();
});
}
return promise.promise;
};
I figured it out. Funciton is right but I used below function in my code it was conflicting with this function
$scope.gridOptions.rowIdentity = function(row) {
return row.id;
};

UI Grid column filtering works very slow

I have used UI-Grid's built in cell filters but it takes hell lot of time to filter the data even when I have just 20 records.
<div id="grid1" ui-grid="gridCtrl.gridOptions1"
ui-grid-pagination
ui-grid-pinning
ui-grid-resize-columns
ui-grid-move-columns
ui-grid-selection
style="width: 100%; height:680px" class="ui-grid">
and i have just enabled filtering as true.
Please help
actually I found the reason behind this.. I rendered all my rows at once with virtualization Threshold = number of rows, this does not allow the default ui grid rendering algorithm to be used.
Here is a potential workaround...
1. In ui-grid.js, remove the watches set up for each column filter in the header. See if this removes the sluggishness. It will also make the grid not respond to filter changes. Continue to steps 2-4 to make the filters work again.
//$scope.col.filters.forEach(function (filter, i) {
//filterDeregisters.push($scope.$watch('col.filters[' + i + '].term', function(n, o) {
// if (n !== o) {
// uiGridCtrl.grid.api.core.raise.filterChanged();
// uiGridCtrl.grid.api.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
// uiGridCtrl.grid.queueGridRefresh();
// }
//}));
//});
2. In your code, create a function that iterates through the filter terms of each column and creates a string of all filter terms.
function getConcatenatedFilter() {
var concatenatedFilter = "";
var api = this.getGridApi();
if (api) {
for (var i = 0; i < api.grid.columns.length; i++) {
concatenatedFilter += i + ":";
var column = api.grid.columns[i];
var term = column.filters[0].term || "";
if (term) {
concatenatedFilter += term;
}
}
}
return concatenatedFilter;
}
3. Create one watch that monitors the concatenated filter function above. When it fires, create a timeout to that sets another scope variable called filtersCheck. The timeout will wait 200ms before changing filtersCheck.
$scope.$watch(function() {return getConcatenatedFilter();},
function (newVal: string, oldVal: string) {
if (filterTextTimeout) {
$timeout.cancel(filterTextTimeout);
}
var tempFiltersString = newVal;
filterTextTimeout = $timeout(() => {
$scope.filtersCheck = tempFiltersString;
}, 200);
});
4. Finally, set up a final watch for filtersCheck which will refresh the grid when it fires.
$scope.$watch('filtersCheck', (newVal, oldVal) => {
if (newVal && oldVal && newVal !== oldVal) {
gridApi.grid.queueGridRefresh();
}
});

Continuous Looping Page (Not Infinite Scroll)

I'm looking for resources that create scrolling functions like the ones found on these sites:
Outpost Journal
Unfold
Once the scroll bar hits the bottom of the page, I want it to loop back to the top.
I'm familiar with with the infinite scroll, and this is not what I want. I've also found scripts that will write/add the same content to the bottom of the page, but none that loop back to the top of the page.
Try this:
$('document').ready(function() {
$(document).scroll(function(){
if(document.documentElement.clientHeight +
$(document).scrollTop() >= document.body.offsetHeight )$(document).scrollTop(0);
});
});
if you want infinite scroll in both directions use
if (document.documentElement.clientHeight + $(window).scrollTop() >= $(document).height()) {
$(document).scrollTop(0)
} else if ($(window).scrollTop() < 0) {
$(document).scrollTop($(document).height())
}
(I know it's a late reply but it still helps users like me who just google stuff like this)
Here a solution that makes a duplicate of the body so the bottom and the top can be seen at the same time at a certain point so the transition is smoother.
$('document').ready(function() {
// We need to duplicate the whole body of the website so if you scroll down you can see both the bottom and the top at the same time. Before we do this we need to know the original height of the website.
var origDocHeight = document.body.offsetHeight;
// now we know the height we can duplicate the body
$("body").contents().clone().appendTo("body");
$(document).scroll(function(){ // detect scrolling
var scrollWindowPos = $(document).scrollTop(); // store how far we have scrolled
if(scrollWindowPos >= origDocHeight ) { // if we scrolled further then the original doc height
$(document).scrollTop(0); // then scroll to the top
}
});
});
mrida's answer was causing my browser to not be able to scroll, here is a modified version that worked for me:
$('document').ready(function() {
$(document).scroll(function(){
if (document.documentElement.clientHeight + $(window).scrollTop() >= $(document).height()) {
$(document).scrollTop(0);
}
});
});
Forked from #clankill3r's answer, create two copy of body, prepend and append to the original body, then you can scroll the page in two direction endless.
$('document').ready(function() {
var origDocHeight = document.body.offsetHeight;
var clone=$("body").contents().clone();
clone.appendTo("body");
clone.prependTo("body");
$(document).scroll(function(){
var scrollWindowPos = $(document).scrollTop();
if(scrollWindowPos >= origDocHeight ) {
$(document).scrollTop(0);
}
if(scrollWindowPos <= 0 ) {
$(document).scrollTop(origDocHeight);
}
});
});
Adding loop scroll backwards, upgrading #clankill3r answer. It should be something like this.
$('document').ready(function() {
// We need to duplicate the whole body of the website so if you scroll down you can see both the bottom and the top at the same time. Before we do this we need to know the original height of the website.
var origDocHeight = document.body.offsetHeight;
// now we know the height we can duplicate the body
$("body").contents().clone().appendTo("body");
$(document).scroll(function(){ // detect scrolling
var scrollWindowPos = $(document).scrollTop(); // store how far we have scrolled
if(scrollWindowPos >= origDocHeight ) { // if we scrolled further then the original doc height
$(document).scrollTop(scrollWindowPos + origDocHeight); // then scroll to the top
} else if (scrollWindowPos == 0) { // if we scrolled backwards
$(document).scrollTop(origDocHeight);
}
});
});
I'm using it horizontally and it's working just fine. Hope someone finds it useful.
Posted a similar question: https://stackoverflow.com/a/65953934/7474712 and found the answer via this pen: https://codepen.io/vincentorback/pen/zxRyzj
Here's the code:
<style>
html,
body {
height: 100%;
overflow: hidden;
}
.infinite {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.clone {
height: 50vw;
}
</style>
<script>
var doc = window.document,
context = doc.querySelector('.infinite'),
clones = context.querySelectorAll('.clone'),
disableScroll = false,
scrollHeight = 0,
scrollPos = 0,
clonesHeight = 0,
i = 0;
function getScrollPos () {
return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}
function setScrollPos (pos) {
context.scrollTop = pos;
}
function getClonesHeight () {
clonesHeight = 0;
for (i = 0; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
function reCalc () {
scrollPos = getScrollPos();
scrollHeight = context.scrollHeight;
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
}
}
function scrollUpdate () {
if (!disableScroll) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= scrollHeight) {
// Scroll to the top when you’ve reached the bottom
setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the bottom when you reach the top
setScrollPos(scrollHeight - clonesHeight);
disableScroll = true;
}
}
if (disableScroll) {
// Disable scroll-jumping for a short time to avoid flickering
window.setTimeout(function () {
disableScroll = false;
}, 40);
}
}
function init () {
reCalc();
context.addEventListener('scroll', function () {
window.requestAnimationFrame(scrollUpdate);
}, false);
window.addEventListener('resize', function () {
window.requestAnimationFrame(reCalc);
}, false);
}
if (document.readyState !== 'loading') {
init()
} else {
doc.addEventListener('DOMContentLoaded', init, false)
}
</script>

Resources