Fade In/Out On Scroll - slideshow

I am trying to get this series of slideshows to fade in/out on scroll.
Trying to get it to do gradual fade but am not getting anywhere with this.
https://thetulip.community/Shannon-Garden-Smith
<script>
$(window).scroll(function() {
$(".image 1").css({
'opacity' : 0.5-(($(this).scrollTop())/20)
});
});
</script>
I tried this but to no avail!
My knowledge of Java is limited, so I'm not sure how to have each one fade in and out on scorll.
Any help would be beyond appreciated.
Thank you,
S

Welcome to the community.
I'm not sure which library you're using for your slideshow presentation, but jQuery has built in methods to fade HTML elements in or out. You can view them here:
https://api.jquery.com/fadeIn/
https://api.jquery.com/fadeout/
Note that each method has an optional function to call once the animation is completed, which is called once per element match. One approach could be to call fadeOut() on click, and then call fadeIn() within the fadeOut method's complete function. For example:
var images = [
"https://freight.cargo.site/w/750/i/0c4f83626e13ce4aa69fee4a84d02618c43afa3ff33d3c6bbd8fd6e265aa5538/01-03-downwrong.jpg",
"https://freight.cargo.site/w/750/i/3aa2564a6c11b13ef5c44820c69b00563e89ddd572372d52d60b6a0bfd80d1bc/01-04-downwrong.jpg"
]
var i = 0;
$(function() {
$('img').attr('src', images[i]);
});
$('img').click(function() {
$(this).fadeOut('slow', function() {
i = i === images.length - 1 ? 0 : i + 1;
$('img').attr('src', images[i]);
$(this).fadeIn('slow');
});
});
Here's a fiddle: https://jsfiddle.net/matthewmeppiel/n28hg4qj/5/

Related

Ionic - How to detect and pass value back to original view with $ionicHistory.goBack();

Using ionic, I am trying to have a use case to select from a list and return back to the original view with some value. I'ved already done most of the part except detecting it has returned to the original view and passing a value back to the original view.
Here's so far what i'ved accomplished:
button that goes to a list
<button class="button button-block button-outline button-positive" ng-click="performselectUnit()"> Select Unit
</button>
this is the trigger to go to the new view with the list
$scope.performselectUnit = function(){
console.log('performselectUnit');
$state.go('app.units');
}
the view with list when press performs an action on the selected row
<ion-item collection-repeat="unit in units" class="item item-icon-right item-icon-left" ng-click="selectUnit(unit.id)">
on selection of the row it goes back to the original view with $ionicHistory.goBack()
$scope.selectUnit = function(unit_id){
console.log('performselectUnit:' + unit_id);
$ionicHistory.goBack();
}
From the last function, how do detect its gone back to the original view and pass some value.
Thanks.
UPDATE:
I tried this.
Broadcast the result
$scope.selectUnit = function(unit_id){
console.log('performselectUnit:' + unit_id);
$ionicHistory.goBack();
$rootScope.$broadcast('selected-unit', { data: unit_id });
}
in the original view controller i capture the event and result.
$rootScope.$on('selected-unit', function(event, args) {
console.log("received selected-unit" + args.data);
$scope.showSelectedUnit = args.data;
});
but it NEVER got updated in the view
<label class="item item-text-wrap">
<button class="button button-block button-outline button-positive" ng-click="performselectUnit()"> Select Unit
</button>
{{showSelectedUnit}}
</label>
How can I get it to update in the view ? or is there a better way
Faced to the exact same issue, I could make it work by switching the order of calls to goBack and broadcast:
$rootScope.$broadcast('selected-unit', { data: unit_id });
$ionicHistory.goBack();
You can use pub-sub service for sharing info between two ctrl
fiddle demo
function MyCtrl($scope, datasharer) {
$scope.sharedData = datasharer.getSharedData();
$scope.send = function() {
datasharer.setSharedData($scope.name);
}
}
function My2Ctrl($scope, datasharer) {
function getSendData(data) {
console.log(data);
$scope.sharedData = data;
}
datasharer.registerForSharedData(getSendData);
}
Using $rootScope.$broadcast and $rootScope.$on should resolve your problem indeed, just use $scope.$apply in $rootScope.$on:
$rootScope.$on('selected-unit', function(event, args) {
console.log("received selected-unit" + args.data);
$scope.$apply(function() {
$scope.showSelectedUnit = args.data;
});
});
What's more, the $rootScope.$broadcast is always expensive, so you could try $rootScope.$emit instead. More about angular event, please refer to https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/.
But the more graceful solution is use Service to share data between controllers, you could refer to Share data between AngularJS controllers.

Binding 'style' to a computed property

I have a component which is inserted into the DOM as a '' tag (e.g., default behaviour). The component's job is to wrap a 3rd party jQuery tool and I'm trying to ensure it is responsive to "resize" events so I would like to explicitly set width and height style attributes.
In the component, it is easy enough to being to the style attribute:
attributeBindings: ['style'],
style: function() {
return "width: auto";
}.property('widthCalc'),
In this case, this works but doesn't do anything useful because style just returns a static string (width: auto).
Instead what I want to do is -- based on any change to the computed property widthCalc -- set the width based on the new value. So here's the next logical step:
style: function() {
var width = $('body')[0].offsetWidth;
return 'width: ' + width + 'px';
}.property('widthCalc'),
This too works, dynamically setting the DIV to the width of the body's width (note: this isn't really what I want but it does prove that this simple binding works). Now what I really want is to get the value of width from a computed property on the component but I don't even have to go that far to run into trouble; notice that instead of a global jQuery selector I switch to a localised component-scoped selector:
style: function() {
var width = this.$().offsetWidth;
return 'width: ' + width + 'px';
}.property('widthCalc'),
Unfortunately this causes the page NOT to load and gives the following error:
Uncaught Error: Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.
I imagine this is Ember run-loop juju but I'm not sure how to proceed. Any help would be appreciated.
Since it is not possible to call this.$() in the component before it has been added to the dom, provide an initial value until the component is ready.
For example,
Setting a default value to the property style and on didInsertElement event reopen the class and define style as a calculated property using this.$()
http://emberjs.jsbin.com/delexoqize/1/edit?html,js,output
js
App.MyCompComponent = Em.Component.extend({
attributeBindings:["style"],
style:"visibility:hidden",
prop1:null,
initializeThisStyle:function(){
this.set("style","visibility:visible");
this.reopen({
style:function(){
// var thisOffsetWidth = this.$().get(0).offsetWidth;
return "visibility:visible;color:red;background-color:lightgrey;width:"+this.get("prop1")+"px";
}.property("prop1")
});
}.on("didInsertElement")
});
Alternatively handle the error raised by this.$() and provide a default value. Afterwards when the component will be added the property will be calculated as planned.
http://emberjs.jsbin.com/hilalapoce/1/edit?html,js,output
js
App.MyCompComponent = Em.Component.extend({
attributeBindings:["style"],
style:function(){
try{
this.$();//this will throw an erro initialy
return "visibility:visible;color:red;background-color:lightgrey;width:"+this.get("prop1")+"px";
}catch(e){
return "color:blue";
}
}.property("prop1"),
prop1:null
});
With the component I was trying to solve for I ended coming up with an solution that seems effective to me which I will share below. For an understanding of the why I was getting the error and how one might more directly address that error please see the comment from #melc above.
My Solution
What I'm solving for is resizing a jQuery component wrapped in an Ember component. In many cases, resizing is handled gracefully by CSS alone but some jQuery components -- including the very nice knob component from aterrien -- has JS which gets directly involved and therefore needs the containers width and height properties to be set explicitly by the Ember component so that it reacts appropriately.
When solving for this I realised my use-case had two problems:
Solving for a page resize event
Adjusting to the fact that my knob component was -- at times -- in the DOM but in a part of the DOM which was not visible (more explicitly it was in Bootstrap tab which wasn't visible).
The Resize Listener
The first part of the solution is to listen for a page-level resize of the page. I do this with the following:
resizeListener: function() {
var self = this;
self.$(window).on('resize', Ember.run.bind(self, self.resizeDidHappen));
}.on('didInsertElement'),
Page Resize Handler
When a resize is done at the "page" level I now want my component to inspect what the resize impact has been on the component:
resizeDidHappen: function() {
Ember.run.debounce(this, function() {
// get dimensions
var newWidth = Number(this.$().parent().get(0).offsetWidth);
var newHeight = Number(this.$().parent().get(0).offsetHeight);
// set instance variables
this.set('width', newWidth);
this.set('height', newWidth);
// reconfigure knob
this.$('.knob').trigger(
'configure',
{
width: newWidth,
height: newWidth
}
);
}, 300);
}
This solves the page resize problem if it exists in isolation but to make the component it is probably a good idea to solve for the visibility use case as well (certainly in my case it was critical).
Visibility Handler
Why? Well, for two reasons that I can think of:
Many jQuery components refuse to load or perform badly if they aren't loaded
The ember component appears to not be able to establish a "resize" event when it is not visible in the DOM
The one problem is that there is no DOM-level event for visibility changes, so how do we react to a change in visibility without polling on an interval? Well in most cases there will be a UI element which is controlling the state of visibility. In my case it's Bootstrap's tab bar and in this case they have events that fire on the tabs when they become visible. Great. Here's a selector for Bootstrap's selector (assuming you're inside the content area of the newly visible tab):
visibilityEventEmitter: function(context) {
// since there is no specific DOM event for a change in visibility we must rely on
// whatever component is creating this change to notify us via a bespoke event
// this function is setup for a Bootstrap tab pane; for other event emmitters you will have to build your own
try {
var thisTabPane = context.$().closest('.tab-pane').attr('id');
var $emitter = context.$().closest('.tab-content').siblings('[role=tabpanel]').find('li a[aria-controls=' + thisTabPane + ']');
return $emitter;
} catch(e) {
console.log('Problem getting event emitter: %o', e);
}
return false;
},
visibilityEventName: 'shown.bs.tab',
then we just need to add the following code:
_init: function() {
var isVisible = this.$().get(0).offsetWidth > 0;
if (isVisible) {
this.visibilityDidHappen();
}
}.on('didInsertElement'),
visibilityListener: function() {
// Listen for visibility event and signal a resize when it happens
// note: this listener is placed on a DOM element which is assumed
// to always be visibile so no need to wait on placing this listener
var self = this;
Ember.run.schedule('afterRender', function() {
var $selector = self.get('visibilityEventEmitter')(self);
$selector.on(self.get('visibilityEventName'), Ember.run.bind(self, self.visibilityDidHappen ));
});
}.on('didInsertElement'),
visibilityDidHappen: function() {
// On the first visibility event, the component must be initialised
if(!this.get('isInitialised')) {
this.initiateKnob();
} else {
// force a resize assessment as window sizing may have changed
// since last time component was visible
this.resizeDidHappen();
}
},
Note that this also results in a tiny refactor of our resize listener, removing it's trigger from the didInsertElement event and instead being triggered by initiateKnob which will happen not when the Ember component loads but instead lazy load at the first point of visibility in the DOM.
initiateKnob: function() {
var self = this;
this.set('isInitialised', true);
var options = this.buildOptions();
this.$('.knob').knob(options);
this.syncValue();
this.resizeDidHappen(); // get dimensions initialised on load
console.log('setting resize listener for %s', self.elementId);
self.resizeListener(); // add a listener for future resize events
},
resizeListener: function() {
this.$(window).on('resize', Ember.run.bind(this, this.resizeDidHappen));
},
Does it work?
To a large degree but not completely. Here's what works:
the first 'tab' which is visible at load resizes on demand
all tabs resize when they are switched to (aka, when they gain visibility)
what doesn't work is:
tabs other than the first tab do not resize (aka, the onresize callback appears broken)
The error I get is:
vendor.js:13693 Uncaught TypeError: undefined is not a function
Backburner.run vendor.js:13716
Backburner.join vendor.js:34296
run.join vendor.js:34349
run.bind vendor.js:4759
jQuery.event.dispatch vendor.js:4427
jQuery.event.add.elemData.handle
Not sure what to make of this ... any help would be appreciated. Full code can be found here:
https://gist.github.com/295e7e05c3f2ec92fb45.git

Page loading before transition effects happen

I finally got PJAX all setup and working perfect on my Foundation 5 site and its time to add my page transitions. For some reason no matter what I try the page loads and then the transition happens.
Here is my website with with one of the transitions I tried
I've also tried simple things like:
$(document)
.on('pjax:start', function() { $('#main').fadeOut(200); })
.on('pjax:end', function() { $('#main').fadeIn(200); })
I also ran into aenism.com/teleportation-is-scary/ in my searches for a solution and its what I currently have running on my pages.
Here is an example of it working: Demo Site
I'm not sure what the problem could be at this point.
I found a solution that works perfect for fading out and back in again. I have not tested it with other animations but it looks like it should do the trick. I hope this helps someone else!
// USER CLICKS LINK WITH PJAX CLASS
$('body').delegate('a.pjax', 'click', function() {
// CONTENT FADE OUT TRANSITION BEGINS
$('#main-content').fadeOut(300, function() {
// CALLBACK TO RUN PJAX AFTER FADEOUT
$.pjax({
url: target,
container: '#main-content',
fragment: '#main-content'
})
})
// STOP THE LINK FROM WORKING NORMALLY
return false;
})
// PJAX DOIN THANGS TO THE CONTENT FRAGMENT IDENTIFIED ABOVE
$('#main-content')
.on('pjax:start', function() {
// KEEPING THE MAIN CONTENT HIDDEN
$(this).fadeOut(0)
})
.on('pjax:end', function() {
// FADE IN THE MAIN CONTENT
$(this).fadeIn(300)
// FUNCTIONS LOADED AGAIN AFTER PJAX ENDS GO HERE
})
WOOO That suggestion worked, had to tweak it a bunch to get it to fit with my page transitions, but this is what I ended up with (works off of css3 animations):
$("body").delegate('a[data-pjax]', 'click', function(event) {
var target = $(this).attr("href");
if (contentpage == "true" || errorpage == "true") { $(".contentimage").append('<div class="pjax-loading"></div>'); }
$("body").removeClass("pjax-fadeIn").addClass("pjax-fadeOut").one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(){
$.pjax({url: target, container: '#content', fragment: '#content'});
});
return false;
})
$("#content").on('pjax:start', function() {
$("body").removeClass("pjax-fadeOut").addClass("pjax-hide");
}).on('pjax:complete', function() {
$("body").removeClass("pjax-hide").addClass("pjax-fadeIn");
});

Ember - Clearing an ArrayProxy

On the Ember MVC TodoApp there is an option "Clear all Completed".
I've been trying to do a simple "Clear All".
I've tried multiple things, none of them work as I expected (clearing the data, the local storage and refreshing the UI).
The ones that comes with the sample is this code below:
clearCompleted: function () {
this.filterProperty(
'completed', true
).forEach(this.removeObject, this);
},
My basic test, that I expected to work was this one:
clearAll: function () {
this.forEach(this.removeObject, this);
},
Though, it's leaving some items behind.
If I click the button that calls this function in the Entries controller a couple times the list ends up being empty. I have no clue what's going on! And don't want to do a 'workaround'.
The clearCompleted works perfectly by the way.
The answer depends on what you really want to know-- if you want to clear an ArrayProxy, as per the question title, you just call clear() on the ArrayProxy instance e.g.:
var stuff = ['apple', 'orange', 'banana'];
var ap = Ember.ArrayProxy.create({ content: Ember.A(stuff) });
ap.get('length'); // => 3
ap.clear();
ap.get('length'); // => 0
This way you're not touching the content property directly and any observers are notified (you'll notice on the TodoMVC example that the screen updates if you type Todos.router.entriesController.clear() in the console).
If you're specifically asking about the TodoMVC Ember example you're at the mercy of the quick and dirty "Store" implementation... if you did as above you'll see when you refresh the page the item's return since there is no binding or observing being done between the entry "controller" and the Store (kinda dumb since it's one of Ember's strengths but meh whatev)
Anywho... a "clearAll" method on the entriesController like you were looking for can be done like this:
clearAll: function() {
this.clear();
this.store.findAll().forEach(this.removeObject, this);
}
Well, this worked:
clearAll: function () {
for (var i = this.content.length - 1; i >= 0; i--) {
this.removeObject(this.content[i]);
}
},
If someone can confirm if it's the right way to do it that would be great!

When is the template (.tpl) rendered for an Ext JS Component?

I am trying to inject another component into an element that is rendered by the template of another Coomponent..but in the afterrender event, the template is yet to be rendered so the call to Ext.get(el-id) returns null: TypeError el is null.
tpl:
new Ext.XTemplate(
'<tpl for=".">',
'<ul>',
'<li class="lang" id="cultureSelector-li"></li>',
'</ul>',
'</tpl>'
),
listeners: {
afterrender: {
fn: function (cmp) {
console.log(Ext.get('cultureSelector-li')); // < null :[
Ext.create('CultureSelector', {
renderTo: 'cultureSelector-li'
});
}
}
},
So when can I add this component so that the element is targeting has been created in the DOM?
I think it depends on the component that you are working with. For example, the Data Grid View has a "viewready" event that would suite your needs, and depending what you are attempting, the "boxready" function could work for combo box (only the first render though). Other than that, you can either go up through the element's parent classes searching for the XTemplate render function being called (might be in the layout manager) and extend it to fire an event there, or risk a race condition and just do it in a setTimeout() call with a reasonable delay.
I ended up having to do the work myself. So, I now have the template as a property called theTpl, and then rendered it in beforerender, and then i was able to get a handle on the element in afterrender. This seems wholly counter-intuitive, does anyone have any insight?
beforeRender: {
fn: function (me) {
me.update(me.theTpl.apply({}));
}
},
edit in fact I just extended Component thus:
Ext.define('Ext.ux.TemplatedComponent', {
extend: 'Ext.Component',
alias: 'widget.templatedComponent',
template: undefined,
beforeRender: function () {
var me = this;
var template = new Ext.XTemplate(me.template || '');
me.update(template.apply(me.data || {}));
me.callParent();
}
})
...template accepts an array of html fragments
Turns out I was using the wrong things - apparently we should be using the render* configs for this type of thing (so what are thetpl & data configs for?)
Here's a working fiddle provided for me from the sencha forums:
http://jsfiddle.net/qUudA/10/