Open jorjordandan opened 9 years ago
I'd appreciate this as well — haven't gone through the source yet, but I'm having trouble getting it to behave properly.
Can you describe a scenario? http://gajus.com/sandbox/swing/examples/card-state/ Example shows how to throw out card. Throw in would be close to the same.
What I was trying to do was add cards to the bottom of the stack without throwing them in. I eventually added an extra targetPosition
argument to the createCard
function... but i never actually got it working. I can make a fork to show what I did, but not sure how helpful that will be since it didn't work.
any updates or examples on this? What would be nice is to add cards to the bottom of the stack as cards are swiped from the top
I've been looking into how to dynamically add new cards to the bottom of the stack, and I seem to have something working.
As far as I can tell, the issue seems to be a combination of two things: HTML display order (in the absence of declared z-indexes, nodes at the bottom of the tree appear on top of nodes earlier in the tree), and the Card object's appendToParent
method, which moves any new card to the bottom of the tree (and thus the top of the visual stack).
My solution was to remove the appendToParent
call from createCard
, and replace it with a new method called insertBelow
, which uses parent.insertBefore(element,parent.firstChild)
to add the card to the top of the node list (and thus the bottom of the visual stack). In the case of my prototype, this has the added benefit of the visual stack order matching the order of the JSON data that I'm using to generate the cards.
I declared the new method directly after appendToParent
:
Card.insertBelow = function (element) {
var parent = element.parentNode;
parent.removeChild(element);
parent.insertBefore(element,parent.firstChild);
};
(Originally I attempted to alter appendToParent
, but then I realized it was also being used for when a thrown card is picked up again. That's why I decided to make the new insertBelow
method and leave appendToParent
as it was. I also tried reversing the order of the array being used to create the cards, but that only ever had the illusion of effectiveness.)
Code-wise, I don't know if this is a good solution, since it adds an extra DOM manipulation everytime a card is added (whereas appendToParent
seems to only act if the card is not at the bottom of the node tree, which is always the case when generating a new stack). And I haven't really tested it yet. But it's working so far, in both a plain JS prototype and an AngularJS prototype, so maybe it could be of use to people?
Nice! I will have to try that out later in a meteor project I was working on.
@ronobot: do you have some working code to provide? I'm faving the same issue than you... Thanks a lot!
@HugoHeneault The project I was working on this for got indefinitely delayed, so I wasn't able to test it further. But basically what I did was:
l.appendToParent(e)
with l.insertBelow(e)
i.appendToParent
function:i.insertBelow = function(t) {
var e = t.parentNode;
e.removeChild(t);
e.insertBefore(t,e.firstChild);
}
That's it—now the createCard method uses insertBelow instead of appendToParent.
Has anyone ever managed to make this work? I want to be able to add a card to the bottom of the stack, and addCard
adds it to the top.
I have some working prototype. Maybe it might help you (please note that, this is pseudocode):
var cards = []; // In a list
var queue = []; // In a queue
var stackMaxLength = 2;
var stack = Swing.Stack();
var ul = document.querySelector('ul.stack'); // Should be initially empty
var allCards = [
document.createElement('ul'),
document.createElement('ul'),
document.createElement('ul'),
document.createElement('ul'),
document.createElement('ul')
];
allCards.forEach(addOrKeep);
function addOrKeep(element) {
if (cards.length < stackMaxLength) {
cards.push(card);
// Adding element to DOM tree, as far as I remember to create it have to be in a DOM tree.
ul.prepend(element);
var card = stack.createCard(element);
// On front
ul.prepend(element);
card.on('throwout', function () {
var card = queue.shift();
if (card) {
stackMaxLength++;
addOrKeep(card);
}
});
} else {
// We don't want to have it in a DOM.
card.$element.remove();
queue.push(card);
}
}
If you want me to make it working example, let me know.
If you have some time to implement it, it'll be really awesome!!
2016-01-07 23:30 GMT+01:00 Artur Delura notifications@github.com:
I have some working prototype. Maybe it might help you (please note that, this is pseudocode):
var cards = []; // In a listvar queue = []; // In a queuevar stackMaxLength = 2; var stack = Swing.Stack();var ul = document.querySelector('ul.stack'); // Should be initially empty var allCards = [ document.createElement('ul'), document.createElement('ul'), document.createElement('ul'), document.createElement('ul'), document.createElement('ul') ]; allCards.forEach(addOrKeep); function addOrKeep(element) { if (cards.length < stackMaxLength) { cards.push(card);
// Adding element to DOM tree, as far as I remember to create it have to be in a DOM tree. ul.prepend(element); var card = stack.createCard(element); // On front ul.prepend(element); card.on('throwout', function () { var card = queue.shift(); if (card) { stackMaxLength++; addOrKeep(card); } }); } else { // We don't want to have it in a DOM. card.$element.remove(); queue.push(card); }
}
If you want me to make it working example, let me know.
— Reply to this email directly or view it on GitHub https://github.com/gajus/swing/issues/4#issuecomment-169827612.
I spent a couple of hours trying to add cards to the stack dynamically but I finally made it!
The problem is the following: When you call the function createCard() the function creates a new Card object and its constructor calls the function appendToParent(), which makes the Card appear on top of all other cards. If you change this function call, you can prepend cards to the stack. An even better solution would be to have two separate functions or a function parameter.
1.) Do what @ronobot suggested: Add a new function called insertBelow() and change the function call in the constructor of Card from appendToParent(..) to insertBelow(...) I uploaded my modified version to Codepen: http://codepen.io/miczed/pen/wMdevy?editors=001
2.) Write a function in JS (I used jQuery) to add a Card to the stack:
function addNewCard(data,id) {
var newCard = $(cardTemplate).clone();
$(newCard).find('.content').html(data);
$(newCard).attr('id','card_' + id);
$('.stack').prepend($(newCard));
stack.createCard(document.getElementById('card_' + id));
}
I'm no JS / jQuery expert so this might not be best practice but it seems to work so far.
I have a working extended example here: http://codepen.io/miczed/pen/yebbKE
Hope this helps someone out and thanks to @gajus for the awesome plugin!
tried the first solution . I am unable to get it working . In my case I do not add cards one by one. Cards are created when i initialize it with an array from an API call. One more card is thrown out when first card is thrown out. What does e.removeChild(t);
do in insertBelow
function ?
This is my card.js
Card.insertBelow = function (element) {
var parentNode = element.parentNode;
parentNode.removeChild(element);
parentNode.insertBefore(element, parentNode.firstChild);
};
in construct
Card.insertBelow(targetElement);
Please help.
The issue was caused by pop()
on array, which had to be replaced by shift()
Hey guys,
Having a similar issue...
I'm looking to add cards into the stack when a checkbox is turned on.
When a user clicks a checkbox, the associated cards are entered into the stack and users are able to swipe through them.
I can't seem to get the card stack to update when the selectedCards
array is updated.
Would appreciate any help / advice.
Cheers
`export default class Cards extends Component { constructor(props, context) { super(props, context); this.config = { throwOutDistance: () => Math.max(window.innerWidth, window.innerHeight), throwOutConfidence: () => 1, allowedDirections: [ Direction.LEFT, Direction.RIGHT, ] };
const fakeEvent = {
target: {
id: 'digiDesign',
}
};
this.cardRefs = new Map();
this.state = {
selectedCategories: ['digiDesign', 'branding'],
selectedCards: this.filterArray(fakeEvent),
cardStack: cardData,
currentCard: cardData.length - 1,
cardIndex: 0,
checked: false,
};
}
componentDidMount() { const { selectedCards } = this.state;
//Intiates key listener
document.addEventListener("keydown", this.onDirection);
//Configures Swing.js
this.stack = Stack(this.config);
this.stack.on("dragstart", () => this.setState({ dragging: true }));
this.stack.on("dragend", () => this.setState({ dragging: false }));
this.stack.on("throwout", this.onThrowOut.bind(this));
//Config stack of cards
this.configStack();
//Logs initial cards
console.log(selectedCards, 'selected cards')
}
componentWillUnmount() { this.cardRefs.forEach((ref, i) => { const el = ReactDOM.findDOMNode(this.cardRefs.get(i)); const card = this.stack.getCard(el); card.destroy(); }); }
configStack(){ const {selectedCards} = this.state; this.cardRefs.forEach((ref, i) => { const el = ReactDOM.findDOMNode(this.cardRefs.get(i)); this.stack.createCard(el, true); });
this.setState({
currentCard: selectedCards.length - 1
})
}
//Controls keycodes onDirection = e => { if(e.keyCode === 37){ this.throwoutLeft(); } if (e.keyCode === 39) { this.throwoutRight(); } }
//Controls throwout right with key throwoutRight(){ const el = ReactDOM.findDOMNode( this.cardRefs.get(this.state.currentCard) ); const card = this.stack.getCard(el); card.throwOut(1000, 0); }
//Controls throwout left with key throwoutLeft(){ const el = ReactDOM.findDOMNode( this.cardRefs.get(this.state.currentCard) ); const card = this.stack.getCard(el); card.throwOut(-1000, 0); }
//Controls swipe/grab onThrowOut() { const { currentCard } = this.state const activeCard = this.state.currentCard
if (activeCard > 0){
this.setState({
currentCard: activeCard - 1
})
}
if (activeCard === 0){
this.setState({
currentCard: activeCard - 1
})
this.resetDeck();
}
const card = this.cardRefs.get(currentCard)
console.log(card.props, 'thrown out')
}
//Resets the deck on finish resetDeck() { const { cardStack } = this.state
this.setState({
currentCard:cardStack.length - 1,
resetting: true
});
this.cardRefs.forEach((ref, i) => {
const el = ReactDOM.findDOMNode(this.cardRefs.get(i));
const card = this.stack.getCard(el);
card.throwIn(0, 0);
});
this.setState({
resetting: false,
});
}
//Controls checkboxes filterArray(e){ let filteredArray = cardData.filter(function(x){ return x.id === e.target.id }); return filteredArray }
removeArray(e){ const{ selectedCards } = this.state; for (let i = selectedCards.length-1; i >= 0; i--){ if(selectedCards[i].id === e.target.id){ selectedCards.splice(i, 1) } } }
handleChange(e){ const{ selectedCards } = this.state;
if (e.target.checked){
for (let i = 0; i < this.filterArray(e).length; i++){
selectedCards.push(this.filterArray(e)[i])
}
} if (!e.target.checked){
this.removeArray(e);
}
this.setState({
selectedCards
})
console.log(selectedCards, 'selected cards')
}
render() { const { selectedCards } = this.state; return (
);
} }`
I've got the cards working perfectly in a prototype Meteor.js app, and I'm trying to add and remove elements from the stack. I haven't spent too much time trying, but I thought it might make a good example. Thanks again!