Adding an event to a list child node - javascript

I have a list in my navigation bar which has a list inside it used as a drop down menu. The overall list is named categories (I know it should have a reference to another page but I am just trying to get the dynamic content working first).
I have an event listener attached to this element which takes the user to a page that displays all categories.
As you hover over this element it displays a list of categories. What i would like to do is to be able to click on one of these and it take the user straight to the category.
This works with my code but only in certain places. In others it takes me to the page which displays all categories.
Here is the code i am using to add the events:
var categoryHeading = document.getElementById('categoriesNav');
dropList = document.createElement("ul");
dropList.setAttribute("id", "categoriesDrop");
categoryHeading.appendChild(dropList);
categoryHeading.addEventListener('click', displayCategoriesPage); //displayCategoriesPage displays a page with all categories listed
categoryHeading.addEventListener("mouseover", function(){
if(dropList){
dropList.style.display = "block";
}
});
categoryHeading.addEventListener("mouseout", function(){
if(dropList){
dropList.style.display = "none";
}
});
var categoryListItems = document.getElementsByClassName("categoryListItem");
for(var i=0; i<categoryListItems.length; i++){
categoryListItems[i].addEventListener("click", function(e){
displaySingleCategory(e); //Displays the page with all items from one category
});
}
Here is the HTML:
<nav>
<ul>
<li id="homeNav"></li>
<li id="categoriesNav">
<a>Categories</a>
<ul id="categoriesDrop">
<li class="categoryListItem">Outdoor</li>
<li class="categoryListItem">Technology</li>
</ul>
</li>
<li id="basket"></li>
<li id="search"></li>
</ul>
</nav>
I am assuming the problem is to do with how my <nav> is laid out. Or where i have added the events.

In Javascript whenever an event is triggered, it's default behaviour is bubbling up through DOM.
In your case, you need to stop the event propagation because you have a click listener in the child li and it's parent that will be executed showing you the categories page instead of specific category page.
Try to put e.stopPropagation(); in your child event listeners.

Related

How can I add a slideDown() animation to newly created elements in my Meteor/Blaze site?

I have two unordered lists that contains a set of li elements. The li elements in each unordered list are represented by an array in my backend with each li element corresponding to an item in the respective array.
When I hit the checkbox on one li element, my backend splices the item from one array and puts it into another. This effectively destroys the li element and recreates it in the other list.
I am trying to call a slide up and slide down animation for when the item disappears and reappears from on list to another. However I am only able to get the slide up animation to work when it leaves one list.
When it appears in the other list, the slide down animation does not work, the element simply pops in.
Is there any way that I can append the slideDown() animation to all newly created li elements? Would it be done through an event listener?
Here is a basic representation of what my code currently looks like:
HTML:
<div>
<ul class="top-list">
<li class="js-checkbox"><input type="checkbox">I am list item number</li>
<li class="js-checkbox"><input type="checkbox">I am list item number</li>
<li class="js-checkbox"><input type="checkbox">I am list item number</li>
</ul>
<ul class="bot-list">
<li class="js-checkbox"><input type="checkbox">I am list item number</li>
<li class="js-checkbox"><input type="checkbox">I am list item number</li>
</ul>
</div>
JavaScript
const target = event.target;
let children1 = target.parentElement;
let input = $(children1).find('.filled-in');
var list = $(children1).parents('li'); //<li> element
var parentList = list.parents('ul'); //<ul> element
var parentDiv = list.parents('div'); //parent div
var findTop = parentDiv.children("ul.top-list"); //find sibling
var findBot = parentDiv.children("ul.bot-list"); //find sibling
if (input[0].checked === false) {
$(list[0]).slideUp(300, function() {
instance.data.changed(instance.data.instruction._id.toString(), 0, true);
$(list[0]).appendTo($(findTop[0]));
$(list[0]).slideDown(300);
});
} else {
$(list[0]).slideUp(300, function() {
instance.data.changed(instance.data.instruction._id.toString(), 0, true);
$(list[0]).appendTo($(findBot[0]));
$(list[0]).slideDown(300);
});
}
Explanation of JavaScript:
If an item is being checked, it gets sent to 'top-list' and send to 'bot-list' if unchecked.
The action of disappearing from the first list gives me the correct slideUp() animation, but since there is JavaScript in my backend doing the actual splice and push of the corresponding item in the array, the slideDown() animation does not register when it appears in the other list.
I hope this is a good enough explanation. Here is also a JSFiddle that shows the animation in action, however it is only for one list. I built it for demonstration purposes.
I don't know if this helps but I was wondering if DOMNodeInserted was a potential solution.
You should have one template for the <ul> rendering one template for each <li>:
<template name="Items>
<ul>
{{#each items}}
{{> Item}}
{{/each}}
</ul>
</template>
<template name="Item">
<li class="item">{{text}}</li>
</template>
Be carefull with the template names Items and Item (there is an S at the end of the first).
This way, everytime a <li> changes, the Item template is rendered.
Make the slide up animation on Template.Item.events:
Template.Item.events({
'click .item'() {
// Slide up
// Edit your database
}
});
Make the slide down animation on Template.Item.onRendered:
Template.Item.onRendered(function (){
// Slide down
});

Adding items dynamically/programmatically to jQuery-ui sortable

I have some jQuery UI Portlets similar to this:
http://jqueryui.com/sortable/#portlets
and what I want is to add dynamically (when user click on a button on the UI) some boxes like this (display as grid) within each portlet:
http://jqueryui.com/sortable/#display-grid
I want to add them to portlet from top to bottom and from left to right, defining the maximum number of "boxes" (items) per row.
Is it possible to do (dynamically add them to each portlet)? if so, how? some ideas?
for example, let's say I have below jquery-ui sortable block in my asp.net mvc4 view (initially empty):
<ul id="sortable">
</ul>
so when user click on a button, I want to add an item Text01 like this:
<li id="Text01" class="ui-state-default">Text01</li>
so after adding it, below sortable block is:
<ul id="sortable">
<li id="Text01" class="ui-state-default">Text01</li>
</ul>
if user click on a button again, I want to add another item to the sortable block, so after adding it, below sortable block is generated:
<ul id="sortable">
<li id="Text01" class="ui-state-default">Text01</li>
<li id="Text02" class="ui-state-default">Text02</li>
</ul>
and so on...
Note that in this example ids and contents are correlative, Text01, Text02... but this is only an example, ids and contents can be different.
Any ideas on how to do this from a jquery function?
I am using jQuery 1.10.2
This looks promising:
http://api.jqueryui.com/sortable/#method-refresh
I haven't tried it, but it seems to imply that you can just add an item to a sortable, then call $('#mysortable').sortable('refresh') to recognize it.
This works. Call appendThing from your button click:
var counter = 1;
function appendThing() {
$("<li id='Text" + counter + "' class='ui-state-default'>Text" + counter + "</li>").appendTo($("#mySortable"));
$("#mySortable").sortable({ refresh: mySortable })
counter++;
};

Linking menu items and jQuery ui tabs together

I am trying to link navigation menu items and jQuery tabs together. That means I have two submenu items just think those are category and item and also I have 2 tabs in my page, those are My category and My Items.
What I am trying to do using this is I want to open My category tab when I click on the link category from submenu and vice versa. And also I want to open My Item tab when I click on the link item from the submenu and vice versa.
I tried it doing with jQuery but can't get to work correctly.
My HTML -
<ul id="new-menu">
<li class="dropdown-holder" id="">
<a>My Menu</a>
<div class="dropdown">
<div class="menu-container">
<div class="menu-link">
my sub menu 1
</div>
<div class="menu-link">
my sub menu 2
</div>
</div>
</div>
</li>
<li class="dropdown-holder" id="">
<a>Category & Item</a>
<div class="dropdown">
<div class="menu-container">
<div class="menu-link">
Category
</div>
<div class="menu-link">
Item
</div>
</div>
</div>
</li>
</ul>
<div id="main">
<ul>
<li>Category</li>
<li>Item</li>
</ul>
<div id="tabs-1">
<p>On the Insert tab, the galleries include items that are designed to coordinate with the overall look of your document. You can use these galleries to insert tables, headers, footers, lists, cover pages, and other document building blocks. When you create pictures, charts, or diagrams, they also coordinate with your.</p>
</div>
<div id="tabs-2">
<p>On the Insert tab, the galleries include other document building blocks. When you create pictures, charts, or diagrams, they also coordinate with your.</p>
</div>
</div>
This is my jQuery:
function setCurrent(element) {
$('div').removeClass('current');
$(element).parent().addClass('current');
}
$('#cat_link').click(function() {
$('#tabs-1').hide();
$('#tabs-2').show();
setCurrent(this);
$('#ui-id-2').parent().removeClass('ui-tabs-active ui-state-active');
$('#ui-id-2').parent().addClass('ui-state-default ui-corner-top');
$('#ui-id-1').parent().removeClass('ui-state-default ui-corner-top');
$('#ui-id-1').parent().addClass('ui-tabs-active ui-state-active');
return false;
});
$('#item_link').click(function() {
$('#tabs-2').hide();
$('#tabs-1').show();
setCurrent(this);
$('#ui-id-1').parent().removeClass('ui-tabs-active ui-state-active');
$('#ui-id-1').parent().addClass('ui-state-default ui-corner-top');
$('#ui-id-2').parent().removeClass('ui-state-default ui-corner-top');
$('#ui-id-2').parent().addClass('ui-tabs-active ui-state-active');
return false;
});
This is JS Fiddle
You can see it is working in some manner but not perfectly. Reverse order also not working. Reverse order mean I need to select submenu item according to clicks on tabs.
UPDATE -
According to above JSFiddle
If I click on category link from submenu category tab is opening but its content display from item tab.
If I click on item link from submenu item tab is opening but its content from category tab.
Hope someone will help me.
Thank you.
You can make it simpler: Use right methods to do the job. You are not utilizing jquery ui tabs events /methods.
$("#main").tabs({
activate: function (event, ui) { // subscribe to tab activate
var target = '.menu-link [data-target=#' + ui.newTab.attr('aria-controls') + ']'; // Get the ID of the tab activated. aria-controls on the rendered tab div will give the id of the tab anchor. so get the target as the menu link which has the data-target as that of the id of the current tab.
addCurrent(target); // set up corresponding menu link
}
});
$('.menu-link a').click(function (e) {
e.preventDefault(); // This is required to prevent the default action on click of an anchor tab.
var target = $(this).data('target'); // Get the target repsective to the clicked menu. This is jquery data() to retreive data attribute value.
$("#main").tabs("option", { //Use right method to do the job. set which tab to be opened by using the jquery ui tabs option overload.
'active': $(target).index() - 1 // set the index of the tab to be opened. Get the index using .index() on the target which is the tab anchor and set that as active.
});
addCurrent(this); // set up style for the current menu link
});
function addCurrent(elem) {
$('.current'). // select the currently activated elements
not($(elem) // but not this one if clicked on itself
.closest('.menu-link') // get the closest(Use this instead of parent(), closest is recommended to parent)
.addClass('current') // add the class to the new menu
).removeClass('current'); // remove from existing ones.
}
Minor addition to your markup adding a data-target on your menu link to point to the tab:
Category
Demo
References:
tabs.activate
closest()
index()
tab options
.not()
This is all you need:
$("#main").tabs();
$('.menu-container .menu-link a').on("click", function() {
// get the position of the menu we clicked inside
var menu_ind = $(this).parents('.dropdown-holder').index();
// if not in the submenu we care about, go about default behavior
if( menu_ind != 1 ) return;
// get the position of the link
var ind = $(this).parents('.menu-link').index();
// activate the corresponding tab
$("#main").tabs('select', ind);
return false;
});
it's just tweaks based on the link I posted.
Fiddle: http://jsfiddle.net/925at/1/
You should include at least a snippet of the HTML that would put your jquery code in context so future visitors don't have to rely on jsfiddle.
It looks like you are calling hide/show on the wrong divs.
If #tabs-1 holds your category content, and #tabs-2 holds your item content, shouldn't clicking on #cat-link show #tabs-1 and not hide it?

Table made from list (<ul>,<li>), how to select a row? (:nth-child())?

I made a table out of a simple list structure:
<html>
<body>
<ul id="Column:0">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
<ul id="Column:1">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
<ul id="Column:2">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
</body>
</html>
Now I want to add a simple .mouseover() to every row, for e.g. changing the color of a row, when hovered. And this is what I figured out, so far:
for (var i = 2; i <= _totalRows; i++) {
var row = $('#TimeTable ul li:nth-child(' + i + ')')
row.each(function() {
$(this).click(function(evt) {
var $target = $(evt.target);
console.log($target.nodeName)
if (evt.target.nodeName == 'DIV') {
console.log(evt.parent('li'));
}
}); //end $(this).click(fn)
}); // end each(fn)
}
I get a set of all <li> objects matching to :nth-child(i) where i is the rows number.
var row = $('#TimeTable ul li:nth-child(' + i + ')')
Now I just iter this set through to add a .click(fn) to every <li>.
This works fine. Every cell has it's .click(fn) attached to it.
But the following, what to do on a click, is where I'm stuck for several hours now:
var $target = $(evt.target);
console.log($target.nodeName)
if (evt.target.nodeName == 'DIV') {
console.log(evt.parent('li'));
}
I simply don't get it to run.
You can actually ignore this gibberish, as it's just the last of several things I already tried here.
What I'm trying to do is simply select every <li> with an id='Row:X' and manipulate its CSS. The best I yet had was, that I can click a cell, but no matter in what row this cell is, the last one gets colored. I remember having used i as the row-index, when that happened, so I might miss some understanding of event-handling here, too.
Use a class name for duplicate groups of elements not an ID. If you give row one a class of "Row1" the selector is simply:
$('.Row1')
Then:
$('#TimeTable li').removeClass('highlight');
$('.Row1').addClass('highlight');
If you just wish to change the color on mouseover:
$('#TimeTable ul li').mouseover(function(){
$(this).css('background','red');
});
$('#TimeTable ul li').mouseout(function(){
$(this).css('background','green');
});
Make your ID's like so: C1R1 (Column1Row1) and so on
JQuery read/google up "jquery each"
JQuery read/google up "jquery bind click"
JQuery read/google up "jquery attr" and "JQuery val()"
This will give you the knowledge to write your own and most importantly understand it better. You will want to achieve the following (your close but no for loop required):
A list which JQuery attaches a click event handler to each LI, and then when the click happens the ID can be retrieved.
PS. There's a time and place for tables, they 9/10 times nearly always better for displaying data than CSS is. If you have a complex multi column row and want fiexed hights and no JS to fix things or do anything smart you can have a table and css :Hover on TR for stying mouse over and out etc. Heights are also constant.
PS. PS. If your data is dynamic and coming from a database and the whole row is an ID from the database I tend to avoid using the html ID attribute for this and make my own. You can retrieve this via attr("myattribute");
NOTE ON CSS and IDS:
Standard practice for ID's are to be used once on a page.
Class for repeatable content
Good luck.

One click handler for multiple buttons and stop propagating event up to parent?

I'm generating a bunch of "li" items as a result of an ajax call. They look like:
<li>
<p>Hello result 1</p>
<button>remove</button>
</li>
<li>
<p>Hello result 2</p>
<button>remove</button>
</li>
...
can I create a single click handler that will get called when any one of the "li" item "button" elements gets clicked, and will also stop propagating the click event up to the "li" parent? Something like:
function btnClicked() {
var liItem = this.parent; // ideally is the <li> whose button was clicked.
return true; // don't let click event go up to <li> parent?
}
----------------- Edit ---------------------
Also, I'm not sure if I'm going to use the button element, might use a clickable div as a button instead - the same techniques should work for both though, right?
Thank you
$('li').click(function(event) {
//do something
event.stopPropagation()
});
This will work in jQuery. You will want to change the li to select only the li items you want.

Categories