I've tried using the jQuery.mmenu-plugin, found here http://mmenu.frebsite.nl/. It works great with pre-defined lists, but how do I handle lists which are updated with jQuery?
Here's an example of an initialized mmenu:
<nav id="menu" class="mm-menu mm-horizontal mm-ismenu mm-hasheader mm-hassearch mm-current mm-opened">
<div class="mm-panel mm-opened mm-current" id="mm-m1-p0">
<ul id="list" class="mm-list">
<li id="1"><a>item 1</a></li>
<li id="2"><a>item 2</a></li>
<li id="3"><a>item 3</a></li>
</ul>
</div>
</nav>
Then I append items to the list the following way:
$("#list").append('<li id="4"><a>"item 4"</a></li>');
The appended (fourth) li-item won't get the same behavior as the li-items defined before initialize the mmenu. This means that items added after the initialization won't work with the search field, as an example.
Is there a way to reinitiate the mmenu or to update the li-items connected to it?
Having looked through the Plugin's (mmenu.js) code briefly, you could alter the JavaScript to listen to the DOM for new <a[href="#id"']> elements:
Adjust:
click( $('a[href="#' + id + '"]', that.$menu), function( e ) {
$opening.trigger( evt );
}
to:
click( $(document).find('a[href="#' + id + '"]', that.$menu ), function( e ) {
$opening.trigger( evt );
}
This'll make sure that the $menu can be used for any Loaded & Non-Loaded DOM elements.
Alternatively, You could reinitialise it:
var $Mmenu = $('#menu'),
$Container = $Mmenu.parent(),
$List = $('#menu #list');
$List.append('<li id="4"><a>"item 4"</a></li>');
var newHtml = $Mmenu.html();
$Mmenu.remove();
$Container.append( newHtml );
$(document).find('#menu').mmenu();
The instance of the plugin is attached to the menu. The counter addon registers an update function on the plugin that is used by the search addon to affect changes in other plugins. e.g. when you type into the search box, it will prune the visible children of the submenus and update the counter.
To wire into this you need the instance of the plugin that is attached to your menu element (because there is an array with the registered update functions)
So, if you have an element like this:
<nav id="menu"></nav>
that you initialized via:
$("#menu").mmenu();
then call the _update() method on the plugin object:
$("#menu").data('mmenu')._update();
'menu' is the id of my menu element
'mmenu' is the name of the plugin
_update() is the magic function that will call all the update functions registered in the updates array
Related
I have a list which users can add items to using a drop down of items. I'm tracking user behavior and want to execute a function each time a user ADDS something to this list (not removes it). The list looks like this:
<ul class="items-list" id="user-items">
<li id="newitem1"></li>
<li id="newitem2"></li>
</ul>
They can add more items to the list with the dropdown, the issue is there are no Jquery selectors for the links to those items, so I am instead trying to detect when items are added to the list.
My attempts so far are:
var listOfItems = $("#user-items").children() - I can count how many items are currently in the list. However I can't work out how to check whether the user has added more items. I am new to Jquery and would appreciate if someone could point me in the right direction here? Thanks
Use DOMSubtreeModified event and check if new element added to DOM.
$("#a").bind("DOMSubtreeModified", function() {
alert("list updated");
});
Demo:
Fiddle
All the values of dropdown can be checked using Jquery .each() before adding new item.
<ul class="items-list" id="user-items">
<li id="newitem1"></li>
<li id="newitem2"></li>
</ul>
Jquery:
$( "li" ).each(function( index ) {
console.log( index + ": " + $( this ).text() );
});
Reference : https://api.jquery.com/each/
You can observe mutations in that specific part of the DOM and do whatever you want when they occur.
Documentation here: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Example:
const itemsList = document.querySelector("#user-items");
const observer = new MutationObserver((mutationList, observer) => {
mutationList.forEach((mutation) => {
if (mutation.type === "childList") {
// Do whatever you want here, I'm just logging that
// a child of the <ul> has been added.
console.log("A child node has been added");
}
});
});
observer.observe(itemsList, { childList: true, subtree: true });
/**
* Just some basic code to add items to the list. Not jQuery, but
* you already have this code I assume, so this is just here to make
* the demo work
*/
const itemAdder = document.querySelector("#add-item");
let itemNumber = 0;
itemAdder.addEventListener("click", (e) => {
itemNumber++;
const listItem = document.createElement("LI");
listItem.setAttribute("id", `user-item-${itemNumber}`);
const listItemText = document.createTextNode(`List item ${itemNumber}`);
listItem.appendChild(listItemText);
itemsList.appendChild(listItem);
});
<ul id="user-items">
</ul>
<button id="add-item">Add Item</button>
You can achieve so by using MutationObserver.The MutationObserver interface provides the ability to watch for changes being made to the DOM tree . It is designed as a replacement for the older Mutation Events feature which was part of the DOM3 Events specification.
here is a working example.
var targetNode = $("#user-items");
function createObserver(callback) {
return new MutationObserver(function (mutationRecords) {
mutationRecords.forEach(callback);
});
}
$("#user-items").each(function () {
var obs = createObserver(function (mutation) {
$(mutation.addedNodes).css("background-color", "green");
});
obs.observe(this, { childList: true });
});
setTimeout(function(){
$("#user-items").append('<li id="newitem3">New One</li>');
},1000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<ul class="items-list" id="user-items">
<li id="newitem1">Old One</li>
<li id="newitem2">Old two</li>
</ul>
I'm new to jquery, ajax and jstree. I'm using jstree to have my <ul> elements look like a tree structure.
I have the <ul> under a div tag of id = "container". When I execute the html file, the div (id = "container") is passed to jstree function as follows:
$(function() {
$('#container').jstree();
});
My html snippet is as follows:
<div id="container">
<ul id = "treeNodes">
<li>Parent
<ul>
<li>Child1
<ul>
<li>child2-1</li>
<li>child2-2</li>
<li>child2-3</li>
<li>child2-4</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
The tree structure is being displayed fine.
I'm trying to write a jquery function that gets the li element's name as an argument.
For example: when I click Parent, the function should recieve "Parent" as an argument or when I click child2-3, the function should get "child2-3" as the argument.
I attempted to create that function, but it doesn't seem to work. Here's my attempt -
$("#treeNodes li").click(function() {
console.log("hello");
console.log(this.innerHTML);
});
The control seems to go to the function calling the jstree(), but the other function doesn't seem to work.
Any help or tips would be appreciated. Thanks in advance.
Making your structure into a JSTree causes new HTML to be created and those new elements have custom classes and new APIs. So, you have to read the documentation to understand how to use the new structure.
If you look at this documentation page, you'll see an example of what you are after, which hinges on a custom changed event. I've reproduced that example, customizing it for your HTML and console output.
$(function() {
$('#container')
// listen for the custom "changed" event on any jstree
.on('changed.jstree', function (e, data) {
// When you click on a JSTree the event appears to fire on the entire tree
// You'll have to iterate the tree nodes for the selected one.
var i, j, r = [];
for(i = 0, j = data.selected.length; i < j; i++) {
r.push(data.instance.get_node(data.selected[i]).text);
}
console.clear();
console.log('Selected: ' + r.join(', '));
})
// create the instance
.jstree();
});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.5/jstree.min.js"></script>
<div id="container">
<ul id = "treeNodes">
<li>Parent
<ul>
<li>Child1
<ul>
<li>child2-1</li>
<li>child2-2</li>
<li>child2-3</li>
<li>child2-4</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
I have read the documentation from the jstree page: https://www.jstree.com/
There is a class from the jstree called jstree-children, from that class you can obtain the value from the list, like this:
$(document).on('click', '.jstree-children ul li', function (e) {
console.log($(this).html());
});
Try this: https://jsfiddle.net/Mantixd/0jwpz2r1/
I've read many tutorials and can't seem to get it right. Ok I know that the jquery click function works when you are doing something to the exact same element but how do you make it effect another and toggle back?
I have a menu and when I click on an item I want the background (body) to change to an image.
Example:
HTML
<body>
<ul class="menu">
<li class="menu-item"><a>item 1</a></li>
<li class="menu-item"><a>item 2</a></li>
<li class="menu-item"><a>item 3</a></li>
</ul>
</body>
JQUERY
$(".menu-item a").click(function () {
$(body).css('background', 'http://example.com/image.png'); <-- first menu item
$(body).css('background', 'http://example.com/image.png'); <-- second menu item
$(body).css('background', 'http://example.com/image.png'); <-- third menu item
});
You can use .index() - DEMO
$("a").on("click", function(e) {
e.preventDefault();
var i = $("li").index( $(this).parent() );
if ( i === 1 ) {
$('body').css('background', 'beige');
} else if ( i === 2 ) {
$('body').css('background', 'honeydew');
} else {
$('body').css('background', 'pink');
}
});
Does this seem about like what you're trying to do?
$(".menu-item a:nth-child(1)").click(function () { // first menu item
$(body).css('background', 'http://example.com/image.png');
});
$(".menu-item a:nth-child(2)").click(function () { // second menu item
$(body).css('background', 'http://example.com/image.png');
});
$(".menu-item a:nth-child(3)").click(function () { // third menu item
$(body).css('background', 'http://example.com/image.png');
});
I don't know what you are trying but I could give you hints.
$(".menu-item a") // is an array/jquery collection of all elements that match the selector
.click(function () { // binds the function now to the click event of every item found
$(this); // is now the currently clicked element
// you can now traversal with $(this) for example
$(this).siblings(); // will be a collection of all surrounding elements
$(this).next(); // is the next element after the current one, can be chained like:
$(this).next().next(); // but I wouldn't recomand
$(this).prev(); // same as next but prev
$(this).parent(); // selects the direct parent element, in your case the li element
$(this).children(); // would select the direct children of the current element
// and so on.... there are much more possibilities
// on every of this possibilities you can do your background change
$("some selector"); // is of course still possible
// i think you are trying to do this:
var menuItems = $(".menu-item a");
menuItems.eq(0).css("background", "url to bg 1");
menuItems.eq(1).css("background", "url to bg 2");
menuItems.eq(2).css("background", "url to bg 3");
})
Look at the Traversing section of the jQuery docu. I would also always recommend to look what jQuery is actually doing. Many people hide behind jQuerys api and have no idea whats happening. This results into many misunderstandings.
You may try something like this
HTML:
<body>
<ul class="menu">
<li class="menu-item"><a name="blue" href="#">item 1</a></li>
<li class="menu-item"><a name="red" href="#">item 2</a></li>
<li class="menu-item"><a name="orange" href="#">item 3</a></li>
</ul>
</body>
CSS:
.red {
background:red;
}
.blue {
background:blue;
}
.orange {
background:orange;
}
Jquery:
$('.menu').on('click', 'a', function () {
var bgColor = $(this).attr('name');
$('body').removeClass().addClass(bgColor);
return false;
});
DEMO
The way I suggest going about this is to grab the position of the element that has been clicked. You can do this by using jQuery's index() function as other posters have suggested. Remember this will give you a zero-based index of the position which means that the position counting starts at 0 as opposed to 1.
Based on the item that has been clicked, you assign a CSS class to the target item which is the body element based on the sample code you provided.
Also, I noticed that your JS comments are still invalid even they were edited. Single line comments in JS use a double forward slash, // whereas multiline comments begin with /* and are closed by */.
This is my solution: http://jsfiddle.net/tgZUK/.
I'm using jQuery UI's sortable for my UL list. Each time the user sorts the list, I want each li element to update it's "position" attribute to it's position in the list.
<ul>
<li position="1">a</li>
<li position="2">b</li>
<li position="3">c</li>
</ul>
So when a user swaps c with a, the position will also update. I tried to use .each but it seems that javascript doesn't follow the order of how the LI elements are displayed but the order of the element's creation.
As mentioned in another answer, using update is all you need:
$(function() {
var $sortable = $('ul').sortable({
update: function(event, ui) {
var counter = 1;
$('li', $sortable).each(function() {
$(this).attr('position', counter);
counter++;
});
}
});
});
Example link
Have you tried :eq selector or index method? Provided you know which li element you're trying to find the position of you could find the position like so:
<ul>
<li id="c">c</li>
<li id="b">b</li>
<li id="a">a</li>
</ul>
var position = $('li#b').index();
You'll want to take advantage of the Sortable "update" event:
$( "ul" ).sortable({
update: function(event, ui) {
var order = $(this).sortable('serialize');
console.info(order);
}
});
You can then use the "serialize" method to pull the updated order of items. One requirement for this to work is that the IDs of each list item contain an underscore, so you'd want to update your HTML to:
<ul>
<li id="position_1">a</li>
<li id="position_2">b</li>
<li id="position_3">c</li>
</ul>
I have a unordered list:
<ul id="sortable">
<li id="1" class="ui-state-default">First x</li>
<li id="2" class="ui-state-default">Second x</li>
<li id="3" class="ui-state-default">Third x</li>
</ul>
I want to remove the <li> from the <ul>. I have handled the click event of the class itemDelete where I try to do a remove but I assume its not working because I can't remove the <li> as a child is calling it?
$('.itemDelete').live("click", function() {
var id = $(this).parent().get(0).id;
$("#" + id).remove();
});
What's the best approach?
Assuming you're using a recent version of jQuery:
$('#sortable').on('click', '.itemDelete', function() {
$(this).closest('li').remove();
});
closest is a little more dynamic than parent (although parent works here as well.) It gets the li that is closest to the current element, upwards in the structure.
Actually, the way you have it as of now, id is going to be undefined, because none of the li's have ids.
why not just do
$(this).parent().remove()
also, don't forget to return false.
You don't have IDs on your <li>s
How about simply
$(this).parent().remove();
What wound up working for me:
Prefix your id attributes with a string or underscore (as others have pointed out)
Since frameworks like jQuery Mobile require that ids be unique across all pages (not just in one page, I prefix with the page name, an underscore, and the numerical id that lets me access records in a database.
Instead of binding to a class or the ul control, use 'on' to bind to the li of the parent list:
$('#sortable').on('dblclick', 'li' function() {
aval = $(this).attr('id').match(/\d+/g); // only want the numbers...
id = aval[0];
name = $(this).text(); // in case you need these for a post...
li = $(this); // so we can remove it from the list after the 'this' object changes inside the ajax call...
// make an ajax call to the server
var jqxhr = $.post( "somepage.php", {name: name, id: id},
function(data) {
li.remove();
$("#sortable").listview("refresh");
},'json').fail(function() { alert("error"); });
return false; // preventDefault doesn't seem to work as well...
});
It could also be looking for the index of the elements with event
$('#sortable').on('click', '.itemDelete', function(e) {
e.preventDefault();
$(e.target.parentElement).parent()[0].remove();
});