I have a scenario in a Vue JS App where I have a list of items which randomly change order after having the user presses a button. I can get the list elements to dynamically change their position with Vue.set however when I add a list transition via the <transition-group> tag the change remains, well, transition-less, and I don't know why.
I am displaying my list of items using the v-for attribute like so:
<transition-group name="shuffle" tag="ul">
<li class="content column" v-for="card in notecards" v-bind:key="card.u_id">
<div v-bind:key="card.u_id" v-on:click="card.show=!card.show">
<transition mode="out-in" name="flip">
<span v-bind:key="card.term" v-if="card.show" class="card-pad box card card-content media">
<div class="media-content has-text-centered">
<strong>{{card.term}}</strong>
</div>
</span>
<span v-bind:key="card.def" v-else class="card card-content box media">
<div class="media-content has-text-centered">
<strong>{{card.def}}</strong>
</div>
</span>
</transition>
</div>
</li>
</transition-group>
The key card.u_id is a unique key for each element. I have also defined the css style "shuffle-move" with the following rule:
shuffle-move{
transition: all 1s;
}
Additionally I am updating the position using a shuffle method in my Vue instance which looks like so:
shuffle_cards: function() {
let entries = this.notecards.length;
while (entries){
let random_index = Math.floor(Math.random() * entries--);
let intermediate = this.notecards[random_index];
Vue.set(this.notecards, random_index, this.notecards[entries]);
Vue.set(this.notecards, entries, intermediate);
}
}
I am using Vue 2.
Where am I going wrong?
You are missing a dot in your css rule:
.shuffle-move{
transition: all 1s;
}
Live example of your code : https://codepen.io/hans-felix/pen/oNXqbKE
Related
A little help here, I'm stuck. I don't know even how to start.
I have this v-for for printing my "contracts".
I'm still not to submerged on vuejs workflow so I'm not being able to work around this.
How can I give a diferent background-color to every col div there? But not randomly, I want for them to keep the color even if the page is reloaded, my aproach was using the id of my contract and doing something with that but I don't understand much about vuejs to know how to do it.
Let's say I want to make a javascript function to give a class depending on the contractType.id, how do I execute that function with each loop? Is there a proper way to do this on vuejs?
<template>
<div class="row" v-if="contractTypes && contractTypes.length > 0">
<div class="col-md-4 c-button" v-for="(contractType, index) in contractTypes" :key="index" #click="choose($event.srcElement.innerHTML, index, contractType.id)">
<div class="col p-4 d-flex flex-column position-static text-center">
<strong class="d-inline-block mb-2 text-primary">World</strong>
<h3 class="mb-0">{{ translations && translations[contractType.id] ? translations[contractType.id].usecasetitle : contractType.usecasetitle }}</h3>
<p class="card-text mb-auto">{{ translations && translations[contractType.id] ? translations[contractType.id].description : contractType.title }}</p>
<button class="btn btn-primary">Click</button>
</div>
</div>
</div>
<div v-else>
<h1>Leider stehen für Sie derzeit keine Verträge zur Auswahl.</h1>
</div>
</template>
If you want custom styles on the different contract types, you can d a method:
/*
* #param {string} contract -- a foo bar
* #return {object} -- Bunch of boolean controlled classes
*/
getContractClasses (contract)
{
return {
'style1': contract === 'a string',
'style2': contract === 'another thing',
'style3': true, // This one is always going to be on and will have a bunch of shared styles between all of them
}
},
Then, in the template,
<h3 :class="getContractClasses(contract)">
Finally, just do the different styles in the style guide in the component housing the v-for.
Also, might I suggest an unwritten rule of sorts to remove all the logic from the template layer, and have that as a method or computed? Reading that long ternary inline is a big "No thank you", from me.
I have a bunch of same elements on the page. All those elements have this particular structure:
<div id="9p" class="col s12 m6 l2 cardmaion globalcardclass">
<div class="card 9p">
<div class="card-content ">
<div class="row card-row">
<!-- a bunch of divs -->
<!-- a line of a card -->
<a data-category="here" class="hidden">
<div style="border-top:2px dotted gray;font-size:18px;background:ivory;margin-top:1px;"
id="belanimation" class="card-line waves-effect waves-green">
Some random text goes here <span class="card-line-q"> x 1</span><span
class="modspan "></span></div>
</a>
<!-- a line of a card -->
<a data-category="here" class="hidden">
<div style="border-top:2px dotted gray;font-size:18px;background:ivory;margin-top:1px;"
id="belanimation" class="card-line waves-effect waves-green">
Some random text goes here <span class="card-line-q"> x 2</span><span
class="modspan "></span></div>
</a>
<!-- a line of a card -->
<a data-category="here" class="hidden">
<div style="border-top:2px dotted gray;font-size:18px;background:ivory;margin-top:1px;"
id="belanimation" class="card-line waves-effect waves-green">
Some random text goes here <span class="card-line-q"> x 2</span><span
class="modspan "></span></div>
</a>
</div>
</div>
</div>
</div>
All the cards (example above) have common class = globalcardclass (it's only way to track that 'card elements')
All lines in a card could be (or not!) contains class = hidden
So I want a script to hide the whole card if all <a> elements (lines) have the class = hidden
If one or two elements (lines) do not have class hidden -- the card is shown.
I need to add another hide class to a particular card if all its children elements have class hidden.
Here I try something but It doesn't work at all. The hard part is... when the card element gets elements (lines) with class hidden that card must show up again...
Please, help.
<script>
$(document).ready(function () {
function FilterHere() {
var emptyCounter = 0
jQuery(".globalcardclass a").each(function () {
if ($(this).is('.hidden')) {
emptyCounter++
}
emptyCounter--
});
if (emptyCounter === 0) {
$(".globalcardclass").hide();
}
}
setTimeout(FilterHere, 2000);
});
</script>
UPD!
Here is new way to solve my problem:
jsfiddle.net/q6cekb18
But it also doesn't work...
UPD 2 (!)
Finally! I've got some progress!
$(".globalcardclass").filter(function(){
return $(this).find(".smoothmaion:visible").length == 0;
}).hide();
That code is working... All the card are hiding... But...
A card (.globalcardclass) is not showing up if 'line' element (.smoothmaion) becomes visible again... How to make it some sort of a... toggle?
Yeah... I can:
<script>
function Filtering()
{
$(".globalcardclass").filter(function(){
return $(this).find(".smoothmaion:visible").length == 0;
}).toggleClass( "hide_hide" )
};
</script>
But... When I use another button to filter different type of elements... That 'toggle' thing brings back that hidden element 'cause it has not change so ... toggle..
What can I do?
I'm trying to select the next element to add the class image-radio-selected with JQuery.
My html is like
<div id="photocall">
#foreach ($photocalls as $photocall)
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
#endforeach
<input>
</div>
Im trying to:
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected'); // working
selected.next('.photocallThumb').addClass('image-radio-selected'); // not working
});
After 2 hours, trying to solve, reading doc,
I'm more confused than when I started...
what am I doing wrong?
One method is you will need to get out of the parent div, then do a next for the parent.
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected');
selected.parent(".d-inline-block").next(".d-inline-block").find('.photocallThumb').addClass('image-radio-selected'); // not working
});
.image-radio-selected{border:1px solid #ff00aa;}
.mx-1{width:100px;height:100px;border:1px solid #000000;}
.d-inline-block{display:inline-block;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="photocall">
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<button type="button" id="mybutton">next</button>
</div>
JQuery's next method selects the next sibling of the selected element. However, since your photocallThumb div is inside a d-inline-block div, it has no siblings. You'd have to go back up a level, then find the next photocallThumb, maybe something like selected.parent().find('.photocallThumb').eq(0).
However, an even better pattern that will help you avoid bugs like these is called templating. Basically, on the client side, you have an html template string, and you pass it data that represent your current state. In your case, you'd pass it an array of javascript objects, each one with an image url and an isSelected boolean. Then, when your state changes, instead of using jquery to try to fix what's changed, you just rerender your template and replace your html element's content with the newly rendered template, and it's now magically in the correct state. This is the pattern favored by large frameworks like React and Angular.
Here's an example from lodash that renders a list of usernames:
// Use the "evaluate" delimiter to execute JavaScript and generate HTML.
var compiled = _.template(
`<% _.forEach(users, function(user) { %>
<li><%- user %></li>
<% }); %>`);
compiled({ 'users': ['fred', 'barney'] });
// => '<li>fred</li><li>barney</li>'
I tried to make an animation, but this not working. Also I tried transition-group. How can I improve this code to do it workable?
It shows two diffetent lists based on category of data from my data.json.js file.
Also with transition-group tag it has error:
<transition-group> children must be keyed: <li>
template
<button #click="switcher = !switcher">SWITCH</button>
<transition name="fade">
<li v-for="elements in myData" v-if="elements.key == getKey()">
<span>{{elements.title}}</span>
</li>
</transition>
script
data() {
return {
switcher: true,
}
getKey(){
if (this.switcher) {
return 'KEY'
} else {
return 'ANOTHER KEY'
}
style
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave {
opacity: 0;
}
children must be keyed: <li>
You can bind :key="index" in <li> element. Try this:
<transition name="fade">
<li v-for="(elements, index) in myData" :key="index" v-if="elements.key = getKey()">
<span>{{elements.title}}</span>
</li>
</transition>
Just to clarify the anser above won't work as you have to use an transition group for multiple list-elements. You then also need a key in the loop but binding the index won't give you the desired effect - always the last element in the list will be animated.
Better use :key="elements.id"
Working with an e-commerce store application with polymer
I'm loading products array using polymer core-ajax and using core-animated pages to display product thumbnail and product detail page (full view) but I only wanted to load the product details when clicking on each product thumb, How can I do this
Find the HTML
<div id="article-content" >
<template is="auto-binding" id="page-template" >
<core-ajax
id="ajaxpolo" auto
url="./json/products.json"
handleAs="json"
on-core-response="{{handleResponse}}" response="{{headerList}}" on-core-response="{{postsLoaded}}">
</core-ajax>
<core-animated-pages id="fpages" flex selected="{{$.polo_cards.selected}}" on-core-animated-pages-transition-end="{{transitionend}}" transitions="cross-fade-all slide-from-right">
<section vertical layout>
<div id="noscroll" fit hero-p>
<div id="container" flex horizontal wrap around-justified layout cross-fade >
<section on-tap="{{selectView}}" id="polo_cards" >
<template repeat="{{item in headerList}}">
<div class="card" vertical center center-justified layout hero-id="item-{{item.id}}" hero?="{{$.polo_cards.selected === item.id || lastSelected === item.id }}" > <span cross-fade hero-transition style="">{{item.name}}</span></div>
</template>
</section>
</div>
</div>
</section>
<template repeat="{{item in headerList}}">
<section vertical layout>
<div class="view" flex vertical center center-justified layout hero-id="item-{{item.id}}" hero?="{{$.polo_cards.selected === item.id || $.polo_cards.selected === 0}}" >
<core-icon-button class="go_back" icon="{{$.polo_cards.selected != 0 ? 'arrow-back' : 'menu'}}" on-tap="{{goback}}"></core-icon-button>
{{item.name}} <span cross-fade class="view-cont" style="height:1000px; overflow:scroll;"></span></div>
</section>
</template>
</core-animated-pages>
</template>
first you would set the auto attribute of core ajax to false. auto="false" that would stop core-ajax from grabbing data by it's self. then set up a on-tap or on-click attribute on the element you want to be the click / tap handler. on-tap="{{getThem}}" then create the function.
getThem: function () {
this.$.ajaxpolo.go();
}
that should get it. hope it helps.
edit: you will want to grab a few more things with your event.
on the click / tap handler add the id of the item you wish to get to a generic attribute. (stay away from normal attributes. ie id, title and so forth) dataId I will call it.
<div on-tap="{{getThem}}" dataId="{{product_id}}"></div>
then in your function you get a few more things with the event as i said before.
getThem: function (event, detail, sender) {
var id = sender.attributes.dataId.value;
// do something with id
}
i just realized i may have misunderstood when you were talking about php. sorry.