In the following code I want to create the functionality of a like button when the svg symbol is clicked. I am having trouble getting the value of sPaper, sPolyFill and sPolyEmpty.
So far as is they return undefined.
I need to integrate the symbolAnim function into the like and unlike function. How can I do this?
var LikeButtonView = BaseButtonView.extend({
template: _.template($('#like-button-test').html()),
sPaper: null,
sPolyFill: null,
sPolyEmpty: null,
initialize: function (options) {
BaseButtonView.prototype.initialize.apply(this, [options]); // inherit from BaseButtonView
this.butn = $("button.heart-icon", this.$el);
this.sPaper = Snap(heartIcon.get(0));
this.sPolyFill = sPaper.select('.symbol-solid');
this.sPolyEmpty = sPaper.select('.symbol-empty');
},
like: function () {
console.log("Like clicked");
if (this.butn.hasClass("isLiked")) {
this.unlike();
} else if (this.butn.hasClass("unliked")){
this.butn.removeClass("unLiked");
this.butn.addClass("isLiked");
this.addBlur();
}
},
unlike: function () {
this.butn.removeClass('isLiked');
this.butn.addClass("unLiked");
this.addBlur();
},
symbolAnim: function(heartIcon, isLiked) {
if (isLiked === false) {
sPolyFill.animate({ transform: 't9,0' }, 300, mina.easeinout);
sPolyEmpty.animate({ transform: 't-9,0' }, 300, mina.easeinout);
} else {
sPolyFill.animate({ transform: 't0,0'}, 300, mina.easeinout);
sPolyEmpty.animate({ transform: 't0,0' }, 300, mina.easeinout);
}
}
});
Ok so I got the object by targeting this.butn
initialize: function (options) {
BaseButtonView.prototype.initialize.apply(this, [options]); // inherit from BaseButtonView
this.butn = $("button.heart-icon", this.$el);
this.svgNode = this.butn.find("svg").get(0);
this.sPaper = Snap(this.svgNode);
this.sPolyFill = this.sPaper.select('.symbol-solid');
this.sPolyEmpty = this.sPaper.select('.symbol-empty');
console.log(this.sPaper);
Now I need to implement the functionality of symbolAnim in the like and unlike funcitons
For my like button function, which is triggered in the event has as "click selector": "like", I have come up with the following. However this only works once. So when I click the button the first time it adds the class liked and removes the class unliked, which is the default for the html element. Then when it is clicked again, it removes the liked class and adds the unliked class. So far it works as desired.
The problem is when I try to click it again, to like it again, and nothing happens. It doesn't call the like function anymore and the class remains the unliked.
What is causing this problem and how can I fix it?
like: function () {
if (this.butn.hasClass("liked")) {
this.unlike();
} else if (this.butn.hasClass("unliked")) {
this.controller();
console.log("Like clicked");
}
},
controller: function () {
this.butn.removeClass("unliked");
this.butn.addClass("liked");
this.sPolyFill.animate({ transform: 't9,0' }, 300, mina.easeinout);
this.sPolyEmpty.animate({ transform: 't-9,0' }, 300, mina.easeinout);
},
unlike: function () {
this.butn.removeClass('liked');
this.butn.addClass("unLiked");
this.sPolyFill.animate({ transform: 't0,0'}, 300, mina.easeinout);
this.sPolyEmpty.animate({ transform: 't0,0' }, 300, mina.easeinout);
console.log("Unliked");
}
Related
I am trying to animate buttons in my application using GSAP. User clicks button and animates the maxWidth of the button. I'd like to have this dynamic and add a percentage of the max width that is set using props. is it possible to pass the prop maxwidth to the gsap timeline? as of now it does not work for me.
props: {
maxWidth: {
type: String,
required: true,
},
},
methods: {
buttonTo(path) {
let tl = this.$gsap.timeline({
onComplete: function () {
pushToPath();
},
});
tl.to(this.$refs.primaryButton, {
duration: 0.6,
ease: 'power2.in',
maxWidth: `calc(${this.maxWidth} + 5%)`,
});
const pushToPath = () => {
this.$router.push({ path: path });
};
},
},
I've run into a similar issue before. The nice thing is that it has nothing to do with the Vue Lifecycle, so the value is available within methods.
There are a couple of things that could be causing this issue. I'd start by making sure your prop, "maxWidth," has "px" or some form of CSS measurement tied to it. CSS calc can't have a plain number within the CSS "calc" function.
Here is an example using your function:
props: {
maxWidth: {
type: String,
required: true,
},
},
methods: {
buttonTo(path) {
let tl = this.$gsap.timeline({
onComplete: function () {
pushToPath();
},
});
tl.to(this.$refs.primaryButton, {
duration: 0.6,
ease: 'power2.in',
maxWidth: `calc(${this.maxWidth}px + 5%)`,
});
const pushToPath = () => {
this.$router.push({ path: path });
};
},
},
You could also switch your prop to be of the type "Number" in case, for some reason, the string is causing issues within the timeline.
If this helps, please let me know!
I have a slider and i want that when the elements of the slider run out, for example, when clicking right and nothing happens because there no more elements it prints "fail". I m using this:
this might help: codepen.io/anon/pen/ZMxevp
$('#status_bar').animate({
left: "+=500px"
}, {
duration: 3000,
specialEasing: {
width: "linear",
height: "easeOutBounce"
},
complete: function () {
console.log("complete")
},
fail: function () {
console.log("fail")
}
});
currently I have the JS below. I'm trying to run the slideout.close(); event with smoothstate onStart. My code is below and i'm currently getting an error in the console. Could someone please help me out.
Thanks.
$(document).ready(function() {
slideout();
});
function slideout() {
var slideout = new Slideout({
'panel': document.getElementById('slideout-content'),
'menu': document.getElementById('slideout-nav'),
'padding': 256,
'tolerance': 70,
'side': 'right'
});
$('.mobile-nav__icon').on('click', function() {
slideout.toggle();
});
}
$(function(){
'use strict';
var options = {
prefetch: true,
cacheLength: 2,
onStart: {
duration: 860,
render: function ($container) {
$container.addClass('is-exiting');
smoothState.restartCSSAnimations();
slideout.close();
}
},
onReady: {
duration: 0,
render: function ($container, $newContent) {
$container.removeClass('is-exiting');
$container.html($newContent);
}
},
onAfter: function() {
slideout();
}
},
smoothState = $('#animate-wrapper').smoothState(options).data('smoothState');
});
You've created a global function called slideout, within which you have a local variable called slideout that is the one that refers to a Slideout object - you can't access that local variable from other functions. When you try to use slideout.close() that is looking for a .close() method on the function.
One fix would be to change the name of the variable or function and make the variable global too, so that you can access it anywhere. But adding more globals is messy.
I think it should be fine to combine all of your code into a single document ready handler, so that everything is in the same scope without needing any globals (you would still need to use a different name for the variable).
I can't test the following because I don't have whatever Slideout is, but:
$(document).ready(function() {
'use strict';
var slideout; // variable that is local to the doc ready handler function
// and accessible to all code within that handler
function initSlideout() { // function renamed
slideout = new Slideout({ // assign to variable declared above
'panel': document.getElementById('slideout-content'),
'menu': document.getElementById('slideout-nav'),
'padding': 256,
'tolerance': 70,
'side': 'right'
});
}
initSlideout();
$('.mobile-nav__icon').on('click', function() {
slideout.toggle();
});
var options = {
prefetch: true,
cacheLength: 2,
onStart: {
duration: 860,
render: function ($container) {
$container.addClass('is-exiting');
smoothState.restartCSSAnimations();
slideout.close();
}
},
onReady: {
duration: 0,
render: function ($container, $newContent) {
$container.removeClass('is-exiting');
$container.html($newContent);
}
},
onAfter: function() {
initSlideout();
}
},
smoothState = $('#animate-wrapper').smoothState(options).data('smoothState');
});
I Load this way:
$('.selector').each(function(){
$(this).qtip({
content: { url: '/qtip.php?'+$(this).attr('rel')+' #'+$(this).attr('div'), text:'<center><img src="/images/loader.gif" alt="loading..." /></center>' },
show: { delay: 700, solo: true,effect: { length: 500 }},
hide: { fixed: true, delay: 200 },
position: {
corner: {
target: 'topRight',
tooltip: 'left'
}
},
show: {
// Show it on click
solo: true // And hide all other tooltips
},
style: {
name: 'light',
width: 730,border: {
width: 4,
radius: 3,
color: '#5588CC'
}
}
});
});
And that looks like if there is a thelay cause of the effect. but qtip.php it's loaded with no delay which is what I really want (to reduce unneeded requests)
Can I delay 300ms before loading qtip.php?
You could set it to use a custom event, then trigger the event after a timeout. The hoverIntent plugin might help, if you want to wait until the mouse stops.
Using hoverIntent:
$(selector).hoverIntent(function() {
$(this).trigger('show-qtip');
}, function() {
$(this).trigger('hide-qtip');
}).qtip({
// ...
show: {
when: { event: 'show-qtip' }
},
hide: {
when: { event: 'hide-qtip' }
}
});
If you want to make hoverIntent wait longer before triggering, you can give it a configuration object with an interval property:
$(selector).hoverIntent({
over: showFunction,
out: hideFunction,
interval: 300 // Don't trigger until the mouse is still for 300ms
});
Without a plugin (I haven't tested this):
(function() { // Create a private scope
var timer = null;
var delay = 300; // Set this to however long you want to wait
$(selector).hover(function() {
var $this = $(this);
timer = setTimeout(function() {
$this.trigger('show-qtip');
}, delay);
}, function() {
if (timer) {
clearTimeout(timer);
}
}).qtip({
// ...
show: {
when: { event: 'show-qtip' }
}
});
})();
Here I just created another param and it's more simple to use, I have tested this in qtip1(not sure about qtip2)
$('.qtip').qtip({
show: {
when: 'mouseover',
//customized param, when 'mouseout' the qtip will not shown and delay will clean
cancel : 'mouseout',
delay: 500
}
});
To add this param, you need to modify the code of function assignEvents() in qtip:
function assignEvents()
{
...
function showMethod(event)
{
if(self.status.disabled === true) return;
// If set, hide tooltip when inactive for delay period
if(self.options.hide.when.event == 'inactive')
{
// Assign each reset event
$(inactiveEvents).each(function()
{
hideTarget.bind(this+'.qtip-inactive', inactiveMethod);
self.elements.content.bind(this+'.qtip-inactive', inactiveMethod);
});
// Start the inactive timer
inactiveMethod();
};
// Clear hide timers
clearTimeout(self.timers.show);
clearTimeout(self.timers.hide);
// line : 1539
// Added code
--------------------------------------------
// Cancel show timers
if(self.options.show.cancel)
{
showTarget.bind(self.options.show.cancel,function(){
clearTimeout(self.timers.show);
});
}
--------------------------------------------
// Start show timer
self.timers.show = setTimeout(function(){ self.show(event); },self.options.show.delay);
};
For qtip2 there is parameter, called show while initializing the plugin, which represents time in milliseconds by which to delay the showing of the tooltip when the show.event is triggered on the show.target.
For example:
/*This tooltip will only show after hovering the `show.target` for 2000ms (2 seconds):*/
jQuery('.selector').qtip({
content: {
text: 'I have a longer delay then default qTips'
},
show: {
delay: 2000
}
});
I have a JavaScript function that I'm passing an argument to, that opens a jQueryUI Dialog. I want the dialog to have either one or two buttons, based on the value of the argument. How should I do this?
So far I've tried:
function foo(hasFile) {
$('#dialog').dialog({
buttons: {
Close: function() { $(this).dialog('close'); },
if (hasFile)
"Download": // do something
}
});
}
and
function foo(hasFile) {
$('#dialog').dialog({
buttons:
if (hasFile)
{
"Download": // do something
Close: function() { $(this).dialog('close'); }
}
else
{
Close: function() { $(this).dialog('close'); }
}
});
}
both of which have thoroughly broken my page.
buttons is a JavaScript literal object. You could do something like this:
function foo(hasFile) {
var buttons = {
Close: function() { $(this).dialog('close'); }
};
if (hasFile) {
buttons.Download = function(){
// Do something.
};
}
$('#dialog').dialog({
buttons: buttons
});
}
A general way to do that is like this:
foo.dialog({
// ...
buttons: (function() {
function CloseHandler() {
// close ...
};
function DownloadHandler() {
// download ...
};
return condition ?
{ "Download": DownloadHandler, "Close": CloseHandler } :
{ "Close": CloseHandler };
})(),
// ...
});
The idea is that you create a function where you can make decisions, and then return the result you decide upon.