I'm trying to enable infinite scroll for an angular-meteor app I'm working on that draws objects from a meteor/mongo collection.
I've adapted step 12 of the angular-meteor tutorial to use pagination for the app I'm working on, and now I'd like to convert to infinite scrolling. I've been trying to adapt both the code from the tutorial and this example from ngInfiniteScroll for my purposes.
I imagine I'll need to use reactive variables, autorun, etc. similar to the tutorial, but I don't really know how to adapt it for infinite scroll. Considering the example below, how should I adjust my controller for it to use infinite scrolling, drawing from a database, with good angular-meteor practices for production?
Demo ngInfiniteScroll HTML:
<div infinite-scroll='loadMore()' infinite-scroll-distance='2'>
<img ng-repeat='image in images' ng-src='http://placehold.it/225x250&text={{image}}'>
</div>
Demo ngInfiniteScroll Function inside controller:
$scope.images = [1, 2, 3, 4, 5, 6, 7, 8];
$scope.loadMore = function() {
var last = $scope.images[$scope.images.length - 1];
for(var i = 1; i <= 8; i++) {
$scope.images.push(last + i);
}
};
My angular-meteor pagination code inside controller:
$scope.page = 1;
$scope.perPage = 1;
$scope.sort = {'_id': -1};
$scope.orderProperty = '1';
$scope.images = $meteor.collection(function() {
return Images.find({}, {
sort : $scope.getReactively('sort')
});
});
$meteor.autorun($scope, function() {
$meteor.subscribe('images', {
limit: parseInt($scope.getReactively('perPage')),
skip: (parseInt($scope.getReactively('page')) - 1) * parseInt($scope.getReactively('perPage')),
sort: $scope.getReactively('sort')
}).then(function(){
$scope.imagesCount = $meteor.object(Counts ,'numberOfImages', false);
});
});
$scope.pageChanged = function(newPage) {
$scope.page = newPage;
};
Please look at this basic example https://github.com/barbatus/ng-infinite-scroll.
Controller there re-subscribes every time onLoadMore is executed.
There is also a deployed demo http://ng-infinite-scroll.meteor.com.
Make sure this time angular.module('infinite-scroll').value('THROTTLE_MILLISECONDS', 500) is set properly (not very small) to avoid very frequent requests.
Related
I was trying to use tick function as described in the below link https://github.com/aframevr/aframe/blob/master/docs/introduction/best-practices.md but it didnt worked out
AFRAME.registerComponent('foo', {
tick: function () {
var el = this.el;
var rotationTmp = this.rotationTmp = this.rotationTmp || {x: 0, y: 0, z: 0};
var rotation = el.getAttribute('rotation');
rotationTmp.x = rotation.x + 0.1;
rotationTmp.y = rotation.y;
rotationTmp.z = rotation.z;
el.setAttribute('rotation', rotationTmp);
}
});
Expected output the object should rotate around x actual result nothing happens..
I hope it's okay if i clarify a bit Kevin's answer.
But first of all, the code is working. Both in aframe 0.9.2 and 0.8.2.
The issue may be related to
the script being placed after the scene is loaded
the component not being attached to the entity:
js:
AFRAME.registerComponent('foo', {
// component body
})
html:
<a-entity foo></a-entity>
As for Kevins answer - it may be a good idea to make changes in the tick function with referring to the underlying THREE.js object.
If you want to rotate a box, there's no need to throw in all that logic you have:
1) create a tmp variable
2) get the object rotation
3) set the tmp variable
4) set the object rotation
When you have a function which executes on each render loop (tick) then you want to minimize what's happening there. So Kevin directly accesses the THREE.js object, and changes the rotation:
tick: function() {
el.object3D.rotation.x += 0.1 * Math.PI / 180 // three uses radians
}
Check it out in this fiddle.
You can just do el.object3D.rotation.x += 0.1
I'm working on my WordPress website with Visual Composer.
I need to include a pageable container but it would be great if it can be like a slideshow.
This is my pageable container
Thanks in advance,
Regards :)
Based upon the current version of WP Bakery Page Builder the below works for me:
To build it I created a row with 3 columns, with the pageable container in the middle column and the left and right arrow images in the columns on either side.
Both arrow images and the pageable container were given IDs. In my example the IDs of the arrows were #arrow_prev and #arrow_next respectively. You can give your pageable container any unique ID.
(function ($) {
$(document).ready(function(){
$( '#arrow_prev' ).click( function( e ) {
var pageable_container = $(this).closest(".vc_row").find(".vc_tta-panels-container");
move_pageable_container(pageable_container,'prev');
});
$( '#arrow_next' ).click( function( e ) {
var pageable_container = $(this).closest(".vc_row").find(".vc_tta-panels-container");
move_pageable_container(pageable_container,'next');
});
function move_pageable_container(pageable_container,direction){
// Make a list of the panel IDs
var panel_ids = $(pageable_container.find(".vc_tta-panel"))
.map(function() { return this.id; }) // convert to set of IDs
.get();
// Find position of the active panel in list
var current_active_pos = panel_ids.indexOf($(pageable_container).find(".vc_tta-panel.vc_active").attr('id'));
var new_pos = 0;
switch(direction) {
case 'prev':
if (current_active_pos > 0){
new_pos = current_active_pos-1;
}else{
new_pos = panel_ids.length-1;
}
break;
case 'next':
if (current_active_pos < panel_ids.length-1){
new_pos = current_active_pos+1;
}else{
new_pos = 0;
}
break;
}
// Clear active panels
$(pageable_container.find(".vc_tta-panel")).each(function(i,a) {
$(this).removeClass("vc_active");
});
var new_active_panel = $(pageable_container).find('#'+ panel_ids[new_pos]);
$(new_active_panel).addClass("vc_animating");
$(new_active_panel).addClass("vc_active");
setTimeout(
function(){
$(new_active_panel).removeClass("vc_animating");
}, 350);
}
}
);
})(jQuery);
If you want a pseudo fading-in effect then you can use this additional CSS in your style sheet:
#id_of_pageable_container .vc_tta-panel.vc_animating {
opacity: 0!important;
}
Where #id_of_pageable_container is the ID that you gave your pageable container
A simpler solution with vanilla js only:
The idea is to find the target page button and press it programmatically, so that there is no need to mimic the plugin's animations as in Chaz's solution.
Add js (via Raw JS widget / other means):
function prevSlide () {
const slides = document.getElementsByClassName('vc_pagination-item');
for (let i = 0; i < slides.length; i++) {
if (slides[i].className.includes('vc_active')) {
if (i - 1 < 0) return;
slides[i - 1].firstChild.click();
return;
}
}
}
function nextSlide () {
const slides = document.getElementsByClassName('vc_pagination-item');
for (let i = 0; i < slides.length; i++) {
if (slides[i].className.includes('vc_active')) {
if (i + 1 >= slides.length) return;
slides[i + 1].firstChild.click();
return;
}
}
}
Add button widgets and set href to call js:
For left arrow button,
javascript:prevSlide();
For right arrow button,
javascript:nextSlide();
Hope this helps.
I prefer to use the Post Grid widget for that. Keep in mind that the pageable container is not totally responsive, it doesn't react to swipe touching, but the Post Grid does.
Post Grid is really powerful, although it also has its caveouts. You can create your content with posts and pages, or a custom post type and then filter what you want to show in your slider from the widget options.
In "advanced mode" you can use the Grid Builder to create your own template and control the output.
The only problems that I've found with this method is to set a variable height in sliders and that sometimes it is slow loading content and is not possible to do a lazyload.
How do I set multiple instances of the nouislider in Meteor?
I have initialed multiple sliders on a page like codes in this . I would like to set the value of sliders synchronized with a collection, but now I am only able to initialized the value with the collection in "start" option.
I've been trying calling a function on 'slide' event. But in the function I find no way to select all the sliders, or use .val().
var updateSliders=function(){
var slider=$(".sliderrr");
console.log(slider);
slider.each(function(){
console.log($(this).val());
})
};
I will base this answer on what you wrote on github
<div class="slider-container">
<div class="sliderrr"></div>
</div>
and
var slider=$(".sliderrr");
slider.each(function(){
console.log("value:",$(this).val());
})
The problem is that you are calling 'each' on the sliderrr instead of the slider-container.
Template.body.rendered = function () {
//init the slider
this.$('.sliderrr').noUiSlider({
start: 5,
connect: "lower",
step: 0,
format: wNumb({
decimals: 0,
}),
range: {
'min': 0,
'max': 30
}
});
//This is the part I changed
var sliderino = this.$('.slider-container');
sliderino.children('.sliderrr').each(function() {
console.log($(this).val());
});
};
Pretty sure I have some fundamental mis-understanding of how/when fa-animate-enter is invoked. The following code works if you click on the box, it scales, but I was expecting that when the fa-view becomes active, it would also call the fa-animate-enter rather than necessitating a click. When a view becomes active, how do I call animateScale_enter()?
http://plnkr.co/edit/r2OSonPSvAQREAHvns7F
<fa-view fa-animate-enter="animateScale_enter()"
fa-animate-leave="animateScale_leave()"
fa-animate-halt="animateScale_halt()" >
<fa-modifier fa-origin="[0.5, 0.5]"
fa-align="[0.5, 0.5]"
fa-scale="scale.get()"
>
<fa-surface fa-background-color="'#dc322f'"
fa-size="[100, 100]"
fa-click="animateScale_enter()"
>{{text}}
</fa-surface>
</fa-modifier>
</fa-view>
.js
<script>
var app=angular.module('MyApp', ['famous.angular'])
.controller('MainController',
function($scope, $famous) {
var Transitionable = $famous['famous/transitions/Transitionable'];
var SpringTransition = $famous['famous/transitions/SpringTransition'];
Transitionable.registerMethod('spring', SpringTransition);
$scope.viewType="view2";
$scope.text="Scale=[1,1,1], click";
$scope.scale = new Transitionable([1, 1, 1]);
$scope.animateScale_enter = function() {
console.log("enter");
$scope.text="Scale=[2,2,1], enter";
$scope.scale.set([2, 2, 1], {
method: 'spring',
period: 750,
dampingRatio: 0.3
});
};
$scope.animateScale_leave = function() {
console.log("leave");
};
$scope.animateScale_halt = function() {
console.log("halt");
scope.transform.halt()
};
}
);
</script>
Apparently it is connected to ng-repeat, and from what I gather, anything that forces a dom update... ??
So just adding a dummy ng-repeat to the fa-view seems to make it work.
<fa-view ng-repeat="x in {x:1}"
fa-animate-enter="animateScale_enter()"
fa-animate-leave="animateScale_leave()"
fa-animate-halt="animateScale_halt()" >
I hope someone can give me a better way to do this. I just feel dirty doing it this way.
I would like to have every template pulse every time it is rendered. To have a visual debugging tool to see what is being rendered. So I imagine something like that when a template (a small segment) is rendered, its background color is set to red and then this red color slowly fades into original background color or whatever the background was (even if it was transparent). So if I see that something is all the time red, I know that it is being redrawn all the time.
Based on the code from #Hubert OG and an idea from this blog post, I made the following debugging code for Meteor rendering:
pulseNode = (i, node) ->
return unless node.style
$node = $(node)
prePulseCss = $node.data('prePulseCss') ? node.style.cssText
prePulseBackgroundColor = $node.data('prePulseBackgroundColor') ? $node.css('backgroundColor')
$node.data(
'prePulseCss': prePulseCss
'prePulseBackgroundColor': prePulseBackgroundColor
).css('backgroundColor', 'rgba(255,0,0,0.5)').stop('pulseQueue', true).animate(
backgroundColor: prePulseBackgroundColor
,
duration: 'slow'
queue: 'pulseQueue'
done: (animation, jumpedToEnd) ->
node.style.cssText = prePulseCss
).dequeue 'pulseQueue'
pulse = (template) ->
$(template.firstNode).nextUntil(template.lastNode).addBack().add(template.lastNode).each pulseNode
_.each Template, (template, name) ->
oldRendered = template.rendered
counter = 0
template.rendered = (args...) ->
console.debug name, "render count: #{ ++counter }"
oldRendered.apply #, args if oldRendered
pulse #
Here's a simple blink. Animating background color requires additional libraries, see jQuery animate backgroundColor .
var pulseNode = function(node) {
if(!node.style) return;
var prev = node.style['background-color'] || 'rgba(255,0,0,0)';
$(node).css('background-color', 'red');
setTimeout(function() {
$(node).css('background-color', prev);
}, 1000);
};
pulse = function(template) {
for(var node = template.firstNode; true; node = node.nextSibling) {
pulseNode(node);
if(node === template.lastNode) return;
}
}
Now, for each template you want to use this, do
Template.asdf.rendered = function() {
pulse(this);
}