phaser drag and drop on multiple text items - javascript

In a game I want to add the numbers 1-9 that are draggable, and on the drag and drop events I want to call some functions. But in a loop events are not working. Any solution will be nice.
Here is the code:
var count = 0;
points.forEach(function(item){
var one = game.add.text(item.centerX, item.centerY, count, this.style);
one.anchor.setTo(0.5)
one.inputEnabled = true;
one.input.enableDrag();
one.input.startDrag(game.input.activePointer);
one.events.onInputDown.add(this.clone, this, 0, one);
one.events.onDragStop.add(this.fixLocation);
count++;
});
This gives me the error:
Phaser.Signal: listener is a required param of add() and should be a Function.
this is the fixlocation function
fixLocation: function(item){
if(rectangle.contains(item.x, item.y)){
itemAdded += 1;
} else{
item.destroy()
}
},

My fault. Acutally the this inside foreach in in wrong context. It is the inside of the loop. All i have to do was to call function outside of the loop. that is:
var count = 0;
var me = this;// get this here
points.forEach(function(item){
var one = game.add.text(item.centerX, item.centerY, count, this.style);
one.anchor.setTo(0.5)
one.inputEnabled = true;
one.input.enableDrag();
one.input.startDrag(game.input.activePointer);
one.events.onInputDown.add(me.clone, this, 0, one); // now call the function
one.events.onDragStop.add(me.fixLocation);
count++;
})

Related

JS - removeEventListener not removing the event

Removing the event does not actually remove it. My guess is it's because of the .bind, it is giving it a different function address when trying to remove the function compared to when adding the function. However, I can not figure out how to give the removeEventListener function the proper address.
document.querySelectorAll(".cell").forEach(function(cell, index){
cell.style.filter = "blur(4px)";
// Adding event
cell.addEventListener("transitionend", cellFadeIn.bind(null, cell, index));
});
function cellFadeIn(cell, index){
if (index == 1){
document.getElementById("heading-wrap").style.transform = "rotate3d(1,0,0,0deg)";
}
cell.style.transition = ".75s";
cell.style.filter = "blur(20px) saturate(110%)";
// Removing event
cell.removeEventListener("transitionend", cellFadeIn);
}
One simple solution is just add a property to the cell to store the index and use this in handler as you normally would when not using bind()
document.querySelectorAll(".cell").forEach(function(cell, index){
// add index to element itself
cell.idx = index;
cell.style.filter = "blur(4px)";
// Adding event
cell.addEventListener("transitionend", cellFadeIn);
});
function cellFadeIn(evt){
if (this.idx == 1){
// idx set above in forEach
document.getElementById("heading-wrap").style.transform = "rotate3d(1,0,0,0deg)";
}
this.style.transition = ".75s";
this.style.filter = "blur(20px) saturate(110%)";
// Removing event
this.removeEventListener("transitionend", cellFadeIn);
}
bind() creates a new and different function. You can assign the binded function to a temporary variable and then use that with removeEventListener().
let bindedCellFadeIn;
document.querySelectorAll(".cell").forEach(function(cell, index){
cell.style.filter = "blur(4px)";
// Adding event
cell.addEventListener("transitionend", bindedCellFadeIn = cellFadeIn.bind(null, cell, index));
});
function cellFadeIn(cell, index){
if (index == 1){
document.getElementById("heading-wrap").style.transform = "rotate3d(1,0,0,0deg)";
}
cell.style.transition = ".75s";
cell.style.filter = "blur(20px) saturate(110%)";
// Removing event
cell.removeEventListener("transitionend", bindedCellFadeIn);
bindedCellFadeIn = undefined;
}

Do I need a parameter in this function?

In this homework assignment, I'm having issues with this part of the problem.
window.onload=setup;
function setup()
{
var questions = document.querySelectorAll('ol li');
for (var i= 0; i < questions.length ; i++)
{
questions[i].id = i + "phrases";
questions[i].onmousedown = showEnglish;
//questions[i].onmouseup = showFrench;
questions[i].style.cursor = "pointer";
}
}
function showEnglish()
{
var phraseNumber = parseInt(question[i].id)
document.getElementById(phraseNumber).innerHTML = english[phraseNumber];
english[phraseNumber].style.font = "italic";
english[phraseNumber].style.Color = "rgb(191,22,31)";
}
a) Using the id property of the list item experiencing the mousedown event, extract the index number with the the parseInt() function and store that value in the phraseNumber variable.
I get an error, saying questions is not defined in the showenglish().
Am I supposed to be referencing another object?
You need to pass the question as a parameter:
for(i=0;i<question.length;i++){
let a=i;//important for scoping
question[a].onmousedown=function(){
showEnglish(question[a]);
}
}
function showEnglish(question){
document.getElementById(question.id).style.font="italic";
...
}
(Note: this answer contains ES6. Do not use it in real productional environment. The let a=i; defines that a is kept for being used inside of the listener, while i will always be question.length, because the event is probably clicked after the loop occured...)
Alternatively, the event listener binds this as the clicked element:
question[i].addEventListener("click",showEnglish,false);
function showEnglish(){
document.getElementById(this.id).style.font="italic";
...
}
The mousedown event is raised when the user presses the mouse button. Look at the documentation for the mousedown event.
Your event handler function will be passed an Event object, which has a target property, which is a reference to the element that the mouse clicked on.
You can access this inside your event handler function with event.target.
window.onload = setup;
function setup() {
var questions = document.querySelectorAll('ol li');
for (var i = 0; i < questions.length; i++) {
questions[i].id = i + "phrases";
questions[i].onmousedown = showEnglish;
//questions[i].onmouseup = showFrench;
questions[i].style.cursor = "pointer";
}
}
function showEnglish(event) {
var phraseNumber = parseInt(event.target.id);
// etc
};

Pass Arguments from One Function to Another Without Calling It

I'm trying to get either options or, ideally, dynamicTable passed from initializeTable to the applyTableFilters function and I'm having problems getting the expected values. I'm using List.js to make a table dynamic and I need to pass or recreate the dynamicTable object so I can go ahead and use it to filter the table.
Here is the function that creates the List.js object from the HTML table:
function initializeTable(options) { // initializes table to be dynamic using List.js functions
var dynamicTable = new List("table-content", options);
dynamicTable.on("updated", function (list) { // writes a message to the user if no results are found
if (list.matchingItems.length == 0) {
document.getElementById("no-results").style.display = "block";
}
else {
document.getElementById("no-results").style.display = "none";
}
});
console.log(dynamicTable);
console.log(options);
console.log(arguments.length);
applyTableFilters.bind();
}
I've tried different methods to pass the variables to the function below. I tried .call, applyTableFilters(args), and .apply, but the problem is that I do not want the function to execute from inside here, only when the click event from the button goes off (not shown in these functions).
This is the function I want to pass the object to and proceed to make the filter functions using it:
function applyTableFilters(dynamicTable) {
var form = document.getElementById("filter-form");
//console.log(options);
//var dynamicTable = new List("table-content", options);
console.log(dynamicTable);
var filters = form.querySelectorAll('input[type="checkbox"]:checked');
dynamicTable.filter(function (item) {
console.log(item);
console.log(item._values);
if (item.values().id == 2) {
return true;
}
else {
return false;
}
//var filterStrings = [];
//console.log(filters);
//for (var i = 0; i < filters.length; i++) {
// var filterVal = filters[i].value;
// var filterString = "(" + item.values().column == filterVal + ")"; // filterVal.contains(item.values().column) ||
// filterStrings.push(filterString);
// console.log(filterVal);
// console.log(filterString);
//}
//console.log(filterStrings);
//var filterString = filterStrings.join(" && ");
//console.log(filterString);
//return filterString;
});
}
I've used:
applyTableFilters.bind(this, dynamicTable/options);
applyTableFilters.bind(null, dynamicTable/options);
applyTableFilters.bind(dynamicTable/options);
Switching between the two since I don't need both passed if one ends up working, etc. I always get a mouse event passed in and that's not even the right type of object I'm looking for. How can I get the right object passed? Also all the values in the first function are not empty and are populated as expected so it's not the original variables being undefined or null. Thanks in advance.
From your initializeTable function return a function that wraps the applyTableFilters function with the arguments you want.
Then assign the returned function to a var to be executed later.
function initializeTable(options) {
var dynamicTable = new List("table-content", options);
// other stuff
return function () {
applyTableFilters(dynamicTable)
}
}
// other stuff
var applyTableFiltersPrep = initializeTable(options)
// later, when you want to execute...
applyTableFiltersPrep()
JSFiddle example

How to Autorun an onclick event

sorry am still learning JavaScript, read W3Cschools javascript and Jquery but there is a lot they don't teach.
I am studying animation at the moment, how do I auto start this rather then wait for someone to click (event listener), I've attempted turning it into a function but I must be doing it wrong, also 1 more what does (Idx) mean, I understand (id) is Html ID element but not sure Idx, not easy to find on google. to read, event listener starts at 5th line from the bottom, and the shuffle cards is 6th line from top (not sure if that helps), original code is located here http://www.the-art-of-web.com/javascript/css-animation/ thanks for any help.
Regards. William.
var cardClick = function(id)
{
if(started) {
showCard(id);
} else {
// shuffle and deal cards
card_value.sort(function() { return Math.round(Math.random()) - 0.5; });
for(i=0; i < 16; i++) {
(function(idx) {
setTimeout(function() { moveToPlace(idx); }, idx * 100);
})(i);
}
started = true;
}
};
// initialise
var stage = document.getElementById(targetId);
var felt = document.createElement("div");
felt.id = "felt";
stage.appendChild(felt);
// template for card
var card = document.createElement("div");
card.innerHTML = "<img src=\"/images/cards/back.png\">";
for(var i=0; i < 16; i++) {
var newCard = card.cloneNode(true);
newCard.fromtop = 15 + 120 * Math.floor(i/4);
newCard.fromleft = 70 + 100 * (i%4);
(function(idx) {
newCard.addEventListener("click", function() { cardClick(idx); }, false);
})(i);
felt.appendChild(newCard);
cards.push(newCard);
I've gone through your code and added comments to try and help explain what is going on in this file:
//Declare card click function. Takes one parameter (id)
var cardClick = function(id){
if(started) {
showCard(id);
} else {
// shuffle and deal cards
card_value.sort(function() {
return Math.round(Math.random()) - 0.5;
});
for(i=0; i < 16; i++) {
(function(idx) {
setTimeout(function() {
moveToPlace(idx);
}, idx * 100);
})(i);
}
started = true;
}
};
// initialise
//set stage as reference to some element
var stage = document.getElementById(targetId);
//append a div with ID "felt" to the stage element
var felt = document.createElement("div");
felt.id = "felt";
stage.appendChild(felt);
// template for card
//declare card variable as a div with some html content
var card = document.createElement("div");
card.innerHTML = "<img src=\"/images/cards/back.png\">";
//Loop from 0 to 16, where i = current value
for(var i=0; i < 16; i++) {
//create a copy of the card made earlier
var newCard = card.cloneNode(true);
//apply some attributes to the new card
newCard.fromtop = 15 + 120 * Math.floor(i/4);
newCard.fromleft = 70 + 100 * (i%4);
//Create and run an anonymous function.
//The function takes one parameter (idx)
//The function is called using (i) as (idx)
(function(idx) {
//add click handler to the card element that triggers the card click
//function with parameter (idx)
newCard.addEventListener("click", function() { cardClick(idx); }, false);
})(i);
//add new card to the stage
felt.appendChild(newCard);
//add new card to an array of cards
cards.push(newCard);
} //end for loop (I added this. It should be here)
how do I auto start this rather then wait for someone to click
The way I would do it, is add a manual click event after the for loop that targets the first card that has the event handler. Because there is no ID set on the cards, I would try using the array that the cards are added to. Assuming that the cards array was empty when we started:
cards[0].click();
If that doesn't work, I would try targeting the item in the DOM. We know that each card is added to the end of div#felt. So, if we can target the first div inside felt, we should be able to trigger the click event on it.
document.getElementByID("felt").firstChild.click();
what does (Idx) mean
I'm hoping the comments help explain this. It looks like the variable idx is just used as an extended reference of i. Inside a for loop, the writer creates a function that takes one parameter (idx). The for loop has a variable (i) that increases by one for each instance of the loop. Each time the loop happens, i is passed into function as idx.
I hope that helps to get you an understanding of how this code works.

How can I reuse an object literal

I'm trying to reuse an object I created to dynamically create more than one slider on a page.
My idea was to create an array and push my slider object there as often as needed, so I could access it by id. Unfortunatelly it doesn't work. Hope someone can point me in the right direction ...
So what I have is this;
var slider = {
"init":function(slide_it){
this.parent = $(slide_it);
/Count Elements and create a navigation depending on the count etc./
},
"otherstuff":{...}
}
In my (document).ready function I create an array and fill it up with different slider objects, add Ids to an accordion and call the init function:
var slide_array = [];
var accordion_sections = $('#accordion > div').length;
for(var i = 0; i < accordion_sections; i++){
slide_array.push(slider);
$('#accordion').children('div').eq(i).attr('id', 'slide_it_'+ i);
slide_array[i].init($('#slide_it_' + i).find('.slider'));
}
Then I have a button with class="next" and I call a function within the slider
$('.next').click(function(){
slide_array[0].otherstuff();
});
My plan is to get the parent of .next and its id so that I can use slide_array[parentID].otherstuff();
But ... it's not working propperly when I call the init function inside the for loop more then once.
More weird, some functions calls seem to work, other have no effect.
What am I doing wrong?
You can use Object.create.
var s1 = Object.create(slider),
s2 = Object.create(slider);
s1.init(...);
s2.init(...);
If you return this from init your will be able to chain like:
var s1 = Object.create(slider).init(...);
However at this point I would just ditch the object literal and use constructors, since this is what you need.
function Slider(slide_it) {
this.parent = $(slide_it);
}
Slider.prototype = {
constructor: Slider,
otherStuff: function () {}
};
var s1 = new Slider(...),
s2 = new Slider(...);
Write a function to return the object:
function slider() {
return {
"init":function(slide_it){
this.parent = $(slide_it);
/Count Elements and create a navigation depending on the count etc./
},
"otherstuff":{...}
};
}
Then:
slide_array.push( slider() );
That'll give you a separate object every time. In you're version, you're filling the array with references to the same single object.
Why not just turn that into a jQuery plugin ?
jQuery.fn.slider = function(options) {
return this.each(function() {
var sliderElem = $(this),
settings = $.extend({
speed : 3000,
something : 'other thing'
}, options);
otherStuff(sliderElem);
});
function otherStuff(elem) {
}
}
$('#accordion > div').slider();
No iteration or jumping through hoops, just call it on the collection and it creates a new slider for each element ?

Categories