I'm creating a memory game using jQuery and PHP (going off a script found here), and essentially what I'm trying to do is make it so that when two cards have been matched, they both are removed. But, I'm using two different images to be paired. In HTML form, each card looks like this:
<div class="card {toggle:'imagename'}">
<div class="off"></div>
<div class="on {toggle:'imageid'}"></div>
</div>
Essentially, when two cards are chosen the jQuery is suppose to check if the id's match. Originally it was suppose to check if the images match, but being two different images I couldn't do that (it'd only display one). Below is the jQuery:
function matchingCards(event, params){
$cards = $("."+params.css_class+".on:visible");
$.each($cards, function(index, card){
var $card = $(card);
$card.trigger("card_removed");
$card.parent(".card").unbind("*").before("<div class='card_ph'></div>").remove();
$card = null;
});
$cards_left = $("#game_board>.card");
if ( $cards_left.length == 0 ){
$(document).trigger("game_won", {});
/*
* quickFlip has a problem when working in IE: when the last
* element bound was removed the problem is caused by the bound
* resize event on the window and is causing
* the end game get stuck when the game is over...
*/
$(window).unbind("resize");
}
$cards_left = $cards = null;
};
function checkCards(){
$on_cards = $("#game_board .card>.on:visible");
if ( $on_cards.length == 2 ){
$(document).trigger("player_made_move");
// Get the first object css class
var css_class = $on_cards.parent(".card").metadata()["toggle"];
var $card = $(this);
var this_card = $card.children(".on").metadata()["toggle"];
$matched_cards = $on_cards.filter("."+this_card);
var event_name = "no_match";
if ( $matched_cards.length == 2 ){
event_name = "found_match";
}
if ( css_class == css_class ){
event_name = "no_match";
}
$(document).trigger(event_name, {css_class: css_class});
$matched_cards = null;
}
clearTimeout(chk_cards_timeout);
chk_cards_timeout = null;
$on_cards = null;
};
Any help would be appreciated.
Additional information:
The pairs have the same image name I just added "_desc" to one of them for the CSS class name (i.e. one image is titled "i1" and the other "i1_desc")
When a pair is found the cards sit there, they don't reset to original position or dissapear.
Try this flow.
1.When a card is clicked...change the class with "open". When is clicked again the class is changed with default one "hidden".
...each card has an id like image_name+desc ...so 2 cards will have the same id.
2.After each click use jQuery each() function to search for "open" class and get the id of the elements.
3) Compare those two ids,if are similar use each() function again to delete the elements. If you are not using each() function you will delete only 1'st element.
ps: don't forget to count, track the ids, score..etc.
...each() function in action http://api.jquery.com/jQuery.each/
Related
I got three classes :
class libro {
var $id;
var $name;
var $editorial;
var $materia = array();
[... getters and setters ]
class editorial {
var $name;
var $id;
[...]
class materia {
var $name;
var $id;
[...]
This is working on a website catalogue, where I got an amount of books I get from an xml file. That works well, I checked it; i receive xml values good.
On my website's catalogue, I got a aside bar. By default, are shown all editorials and materias (categories), as well as all books.
So, when I click on a checkbox of one editorial/materia, page reloads with a new query from xml, where one of them are filtered. Books in catalogue are shown, but on the aside, I need to show only the element I checked in, and the other are grouped researching in the new xml query data.
For example, If I select editorial Great Books, page will reload showing only that one editorial on the checkbox, and on aside's section about Materias I will see all that are contained on the array(materia) inside every book, grouped by to not show repeated categories.
The other way of the example :
If I search by a Materia first, editorials on new query will be grouped by too. If I got Editorial selected and I click a category, only category and editorial selected will be shown, and upside down If I selected first the category.
I'm working with $_GET['editorial'] and $_GET['materia'] to work on new query data.
This is my code about grouping...
$bookList = array();
// Here are methods where I set xml data to classes, and I get an array (link below)
$groupedBookList = array();
foreach ($bookList as $book){
// ERROR IN LINE BELOW (Undefined offset: 0 in ...)
$groupBL_Element = &$groupedBookList[$book->get_editorial()->get_id() . "_" .$libro->get_materia(0)->get_id() ];
$groupBL_Element['editorial'] = $book->get_editorial()->get_id();
$groupBL_Element['materia'] = $book->get_materia(0)->get_id();
}
return array_values($groupedBookList);
goo.gl/ 397Wuz
Someone knows some way to group this? Thanks
The error I get is :
Undefined offset: 0 in (line selected by mine up)
I'm not sure if this is which you are looking for, but if you add to your foreach:
foreach ($bookList as $book){
$groupBL_Element = &$groupedBookList[$book->get_editorial()->get_id() . "_" .$libro->get_materia(0)->get_id() ];
$groupBL_Element['editorial'] = $book->get_editorial()->get_id();
$groupBL_Element['materia'] = $book->get_materia(0)->get_id();
$groupedBookList[] = $groupBL_Element;
}
Then you can return $groupedBookList with our your elements grouped.
I am using Jquery-option-tree plugin on a standalone website not based on Wordpress as in example 7 on the demo page, except that I am not passing a .txt file but a PHP page is generating the array of < options > to be passed to the plugin.
http://kotowicz.net/jquery-option-tree/demo/demo.html
This perfectly works: so let's say that the user wants to select a category for a new product, the plugin suits the purpose generating a nice: " Food -> fruit -> apples " upon user clicks. (see demo page ex. 7)
What instead if a product already exists with its categories assigned? I want to show it to the user when he edit that product, preloading the tree.
I have the ids path coming from database, so it would just be a matter of having the plugin to run without the user interact, using the value I pass. I saw this question: jQuery simulate click event on select option
and tried to simulate user' click with this (and other) methods with no luck.
$('#select')
.val(value)
.trigger('click');
Here the call to the function:
$(function() {
var options = {
empty_value: '',
set_value_on: 'each',
indexed: true, // the data in tree is indexed by values (ids), not by labels
on_each_change: '/js/jquery-option-tree/get-subtree.php', // this file will be called with 'id' parameter, JSON data must be returned
choose: function(level) {
return 'Choose level ' + level;
},
loading_image: '/js/jquery-option-tree/ajax-load.gif',
show_multiple: 10, // if true - will set the size to show all options
choose: ''
};
$.getJSON('/js/jquery-option-tree/get-subtree.php', function(tree) { // initialize the tree by loading the file first
$('input[name=parent_category_id]').optionTree(tree, options);
});
});
Here you can see the plugin:
https://code.google.com/p/jquery-option-tree/
I don't know that plugin, but looking at the examples there seems to be one that fits your need; Example 6 - AJAX lazy loading & setting value on each level change.
This would, in theory, just require some config options:
preselect: {'demo6': ['220','226']}, // array of default values - if on any level option value will be in this list, it will be selected
preselect_only_once: true, // prevent auto selecting whole branch when user maniputales one of branch levels
get_parent_value_if_empty: true,
attr: "id" // we'll use input id instead of name
If this doesn't fit you need though, you could initiate it from an event, like change, keyup, etc.
$(document).on('change', '#select', function() {
$('#nextSelect').val($(this).val());
})
$(document).on('change', '#nextSelect', function() {
$('#finalInput').val($(this).val());
})
Yes, you are right Mackan ! I saw that "preselect" option but I was initially unable to use it transferring the path from database to javascript, I ended up with my "newbie" solution to match the syntax:
preselect: {'parent_category_id': [0,'2','22']},
PHP
$category_path comes from DB query and is like "0,2,76,140,"
$path = explode(',', $category_path);
$preselect="";
foreach ($path as $value) {
$int = (int)$value;
if ($int != 0) $preselect.= "'". $int ."',";
else $preselect.= $int.","; // have to do this as ZERO in my case has to be without apostrophes ''
}
$preselect = "{'parent_category_id':[".$preselect."]}"
JS
var presel= <?php echo($preselect); ?>;
var options = {
preselect: (presel),
}
Any suggestion for a better code ?
Thanks a lot !!
I want to find all child classes with their id in each mother div that is listed per web page.
With that, the id's of the child div's should be grouped by the mainID - to use with an ajax post.
However, I don't even get the child's id's in jquery 1.11, let alone to group them with the mainID.
This is the code so far:
$(".main-column-name").each(function() {
var mainID = $(this).attr('id');
var subid = $(this).find(".subdiv-name").attr("id");
alert(mainID + ' ' + subid );
});
So, under the mainID should be a group of subID's - if they exist of course.
Any help is welcome!!!
You can write it to an object array and attach the children as a sub-array to this.
var mainEl = $(".main-column-name")
mainArr = [],
childArr = [];
//set the properties in an array to be used later
mainEl.each(function() {
var id = $(this).attr('id')
children = $(this).find('.subdiv-name').attr('id');
children.each(function() {
//add the child IDs to an array
childArr.push($(this).attr('id'))
});
//push all the properties into an array
mainArr.push({ 'name': id, 'children': childArr });
});
//to access the properties, use a loop
$.each(mainArr, function (i, value) {
//get the name
console.log(mainArr[i].name);
//get the children
console.log(mainArr[i].children);
//and to access the child IDs individually, use this loop within the loop
$.each(mainArr[i].children, function(c, id) {
//get the stored value for id
console.log(id)
});
});
Use this carefully though, as running a loop within a loop might cause you some performance issues if there will be lots of children and lots of parents. Someone else might be able to advise on a better way of extracting this information other than this... I will update if I think of a better method myself, but I haven't had too much time to look at it.
I have been trying to figure out this problem I've been having all day. I will give you a simplified run down of what I have been trying to do. The user enters a number, and however much the number is, is the number of categories there are going to be on the following page. Within each category, there is an input text button, along with an "Add Textbox" button that adds additional input textboxes dynamically. However, the problem here is that each category has this same setup on the same page. For example, if the user enters the number "3", then the page will vertically load three categories looking something like the following:
Category #1
(Initial user input textbox for category #1)
("Add Textbox" button to allow user to fill out another option)
Category #2
(Initial user input textbox for category #2)
("Add Textbox" button to allow user to fill out another option)
Category #3
(Initial user input textbox for category #3)
("Add Textbox" button to allow user to fill out another option)
The struggle I have been encountering is that each category button will need to have its own function, to tell the button where to place the textbox. This coupled with the fact that the number of categories changes depending on the user's input, has made things difficult. I started with the following:
var categoryCount = <?php echo $categoryCount; ?>;
var click = {};
for (var num=1;num<=categoryCount;num++) {
var newClick = "click_" + num;
click[newClick] = function() {
// some contents when this button is clicked
};
}
This JS creates an object of functions, which in JS would be able to be accessed by doing something like the following:
click['click_' + someID]();
However, the problem is that I cannot do this using the "onclick" attribute in my HTML/PHP button. I cannot access this object of functions, and cannot call any of the individual functions, obviously. I think I am going to need to rethink all of this and start again. I just can't think of another way to get this to work. Please share your ideas with me! Your help would be greatly appreciated.
For something like this, I'd write a constructor I could use like this
var cat1 = new Category(document.body);
Luckily for you, I also wrote one as an example. See the DEMO HERE. I haven't styled it at all for the new lines etc, though.
var Category = (function () {
var categoryCount = 0;
function elem(tag) { // shortcut
return document.createElement(tag);
}
function text(str) { // shortcut
return document.createTextNode(str);
}
function Category(node) {
var self = this; // this should have been var'd, oops!!
this.categoryId = ++categoryCount;
// make add button
this.addButton = elem('button');
this.addButton.appendChild(text('Add Textbox'));
this.addButton.addEventListener('click', function () {
self.addTextbox();
});
// make wrapper
this.wrapper = elem('section');
this.wrapper.setAttribute('id', 'cat'+this.categoryId);
this.wrapper.appendChild(this.addButton);
// make textboxes
this.textboxes = [];
this.addTextbox();
// append to document
if (node) {
this.append(node);
}
}
Category.prototype.addTextbox = function () {
var e = elem('textarea');
e.setAttribute('name', 'cat-'+this.categoryId+'-textbox[]');
this.textboxes.push(e);
this.wrapper.insertBefore(e, this.addButton);
};
Category.prototype.append = function (node) {
return node.appendChild(this.wrapper);
};
return Category;
}());
Here is what I'm doing.
I have a set of divs. Each set of divs can contain a section header and a list of items. Each item has a price associated with it. So item 1 under section Demolition has a price of 150.00. Item 2 under section Demolition has a price of 200.00. Next to each item is an input field that the user can type in a numeric value. That value is then multiplied by the item price. So next to item 1(150.00) is a field where I enter 2. In the next div I then display the total. So 150.00 x 2 = 300.00.
I can do this for each item under the section. I then sum the entire items into one global price next to the sections.
Here is a sample of what I'm doing:
$(document).ready(function() {
$(".demolition_num").each(function() {
$(this).keyup(function(){
calculateDemSum();
});
});
});
function calculateDemSum() {
var sum = 0;
$(".demolition_num").each(function(){
if(!isNaN(this.value) && this.value.lenth != 0){
var unitCost = $(".unit_cost1").text();
var _parent = $(this).parent();
var total = _parent.prev().html();
sum += parseFloat(this.value * total);
var subtotal = this.value * total;
$(_parent).next().html(this.value * total);
}
else if (this.value.length !=0){
}
});
$(".cost1").text(sum.toFixed(2));
$("#cost1").val(sum.toFixed(2));
}
You can view all the code here: http://jsfiddle.net/pmetzger/Xeu2T/3/
As you can see in the jquery that right now I have to call each section independently
of the others since I do not want to calculate all of the fields, just the one I'm modifying.
So the question is, can I avoid having to add each sections input type id as the key up to trigger the calculations and make sure the totals get placed correctly?
Note: This code could be duplicated, but the data associated is going to be different. So on the next clients list it might not be Demolition, but Demo and so forth.
Any help will be greatly appreciated.
First of all a couple of pointers:
You don't need to bind events within an each() loop, simply
binding it to a standard selector will bind to all elements that fit
that selector.
You also have multiple <tr> elements with the same id.
You don't need a size attribute on hidden tags
New working fiddle here and the code:
$(document).ready(function()
{
// Bind the event
$("#calc").on("keyup", "input[type='text']", function()
{
calculateSum(this);
});
});
function calculateSum(element)
{
var sum = 0;
var $this = $(element);
var targetClass = $this.attr("class");
// Process each element with the same class
$("." + targetClass).each(function()
{
var thisVal = $(this).val();
// Count invalid entries as 0
if(isNaN(thisVal) || thisVal.length === 0)
{
thisVal = 0;
}
else
{
thisVal = parseFloat(thisVal);
}
// Get the unit cost and calculate sub-total
var unitCost = parseFloat($(this).parent().prev("td.unit_cost").text());
var subTotal = thisVal * unitCost;
sum += subTotal;
$(this).parent().next("td").text(subTotal);
});
var $item = $this.closest("tr").prevAll(".item").first();
$item.find("input.section_cost").val(sum.toFixed(2));
$item.find("td.section_cost").text(sum.toFixed(2));
}
Note that I have modified your HTML slightly - I changed the multiple <tr id="item"> to use classes, I moved where these rows were to better target your subsection totals, I added classes to the subsection totals (both hidden inputs and displayed values), I added a class to your unit value fields and I added an id to the table.