removing element from mootools sortable - javascript

I'm trying to remove an item from a mootools sortable list, then serialize and save the new list.
I'd like to use a little bit of eye-candy rather than a straight destroy() on the element. I've built a fiddle here: http://jsfiddle.net/kBAqJ/4/
Note the order1 and order2 vars. This holds the serialized element before and after removing the item. If you use the destroy method to get rid of the element after removing it from the sortable, you get the right value for order2, eg. 4.
If you use nix(true) instead of destroy, you get 5 as the value of order1 and order2, even though the docs say that nix(true) calls destroy after dissolve.
Is this a bug in Mootools, or am I missing something? Is there a different way to add a dissolve effect while still using destroy that will get the right result?
window.addEvent('domready', function(){
var mySort = new Sortables('#example2 UL', {
clone: true,
revert: true,
opacity: 0.7
});
console.log (mySort.elements.length);
var order1 = mySort.serialize(0);
console.dir(order1);
mySort.removeItems($('item1')).destroy(); // this results in the correct value in the order2 var below
//mySort.removeItems($('item1')).nix({duration: 1000}, true); // this results in the wrong value for order2
console.log (mySort.elements.length);
var order2 = mySort.serialize(0);
console.dir(order2);
});

i don't think you'll find any effect or way which will destroy the element and still show it on the page ;) So it is not a moo tools bug
The serialize function is using the children of the list (ie. the <li> blocks) to make the array.
I would say the easiest way would be to get rid of their reference in the serialized array:
window.addEvent('domready', function(){
var mySort = new Sortables('#example2 UL', {
clone: true,
revert: true,
opacity: 0.7
});
console.log (mySort.elements.length);
var order1 = mySort.serialize(0);
console.dir(order1);
//mySort.removeItems($('item1')).destroy(); // this results in the correct value in the order2 var below
mySort.removeItems($('item1')).nix({duration: 1000}, true); // this results in the wrong value for order2
console.log (mySort.elements.length);
var order2 = mySort.serialize(0).erase("item1"); // we have to erase the item because he may still be in the list of children at this timeā€¦
console.dir(order2);
});
Cheers

Related

D3 append is not a function when using with VueJS and Vuex

I have a html 'div' and I am trying to append another div to it by the following :
var myDiv = d3.select("#container")
myDiv.append("div")
And I get the following error :
myDiv .append is not a function
Any ideas ? I am using Vuex, so I instantiated the variable in the store and trying to set it to the d3 select.
I have put together a codepen that's similar to what I have : https://codepen.io/anon/pen/oMBGmd?editors=1010
const store = new Vuex.Store({
state: {
networkVariables: {
node: "",
data: [1, 2, 3, 4, 5]
},
container: ""
},
getters: {},
mutations: {}
});
console.log("line 33");
console.log(store);
var networkVariables = store.state.networkVariables;
var container = store.state.container;
container = d3.select("#container");
console.log(networkVariables);
networkVariables.node = container
.selectAll(".node")
.data(networkVariables.data);
console.log(networkVariables.node);
networkVariables.nodeEnter = networkVariables.node.append("div");
In your latest codepen, the error you mentioned is coming from the last line, where you are trying to append to the networkVariable.node directly -- without using the enter selection.
It seems to work for me when I change the last line to be:
networkVariables.nodeEnter = networkVariables.node.enter();
networkVariables.nodeEnter.append("div");
Here networkVariables.nodeEnter = networkVariables.node.append("div");, there is no append() in networkVariables.node object. I tried replacing networkVariables.node.append() with networkVariables.node[0].parentNode.append("div"), this seems to work in the snippet. can you try with this change.
The line in the codepen with the error is like #SteveR noticed the last line.
It is not the result of a d3.select() but a d3.selectAll(..).data(...). The array contains 5 empty placeholders and two fields. These are enter and exit, both functions. To convert this to a "selection" result you have to call one of these functions first before you can append().
But in the original question there should be no problem appending if the tag with the given id exists.
The codepen is not similar to the original question/example.

Sort list from array with jQuery sortable

I know how to save the position of the list elements to a database or localstorage or something similar. But how can I reorder the list with JavaScript from the positions which are saved in my array?
I had a look and StackOverflow and found the following code, but it doesn't work (it just empties my list):
// Get your list items
var items = $('#sortable').find('li');
// The new index order for each item
var order = store.get('sortableIDsOrder');
// Map the existing items to their new positions
var orderedItems = $.map(order, function(value) {
return items.get(value);
});
// Clear the old list items and insert the newly ordered ones
$('#sortable').empty().html(orderedItems);
My array looks like:
[portrait-sms,portrait-pc,portrait-mail,portrait-calendar,portrait-facebook,portrait-twitter,portrait-whatsapp,portrait-skype,portrait-viber,portrait-instagram]
And my HTML looks like:
<li id="portrait-sms"><a href="sms:">...</li>
<li id="portrait-mail"><a href="mailto:">...</li>
<li id="portrait-pc"><a href="#">...</li>
...
The simplest solution I can think of, given only the array (that I assume you've retrieved from somewhere), is:
// assuming this is the array you've recovered from whereever:
var storedArray = ['portrait-sms',
'portrait-pc',
'portrait-mail',
'portrait-calendar',
'portrait-facebook',
'portrait-twitter',
'portrait-whatsapp',
'portrait-skype',
'portrait-viber',
'portrait-instagram'];
function reorder(orderedArray) {
// caching variables:
var el, pre, p;2
// iterating over the elements of the array, using Array.prototype.forEach:
orderedArray.forEach(function (a, b, c) {
// a: the current element in the array,
// b: the index of the current element in the array,
// c: the array itself
if (b > 0) {
// caching the element with the id of the element in the array:
el = document.getElementById(a);
// finding the parentNode of that element:
p = el.parentNode;
// getting the previous element:
pre = document.getElementById(c[b - 1]);
// inserting the element with the id of the current element
// before the nextSibling of the element with the id of the
// previous element in the array:
p.insertBefore(el, pre.nextSibling);
}
});
}
reorder(storedArray);
JS Fiddle demo.
References:
Array.prototype.forEach().
Node.insertBefore().
Node.parentNode.
If you know the elements you have in the database array before hand and they have static values, you can create a new JavaScript array variable by iterating over database array and by forming a new JS array which you use while loading the UI.
On the other hand, if your requirement is to just sort the array during UI loading time instead of showing elements in a fixed order(as retrieved from database), you can use JQuery Table Plugins like DataTable.

Jquery UI sortable retrieve Id and Sortposition

Let me explain my situation:
I've 3 positions where images can be hold. They don't have to be filled all.
Empty div | Img 1 | Img 2
When I change the Img 1 to the second place it would be:
Empty div | Img 2 | Img 1
Sortable works fine with this. But I want to save this to the database. The empty div has no ID or data which I want to use. I only want to use the Img's data. So the Img has a data-imgId attribute or something which I want to pass in an array with Javascript.
I want that in my array the "Current position" and the "Data-imgId" are added.
Something like this:
Array
(
[230] = 2
[120] = 1
)
The 230 and 120 are the imageId's and the 2 and 1 are the sortId's. Now I just can update my database with the where clause on the imageId and then set the sortId on the good sort.
With the next code I can check the item which is moved, but the "automatically" moved other image is not returned. How can I fix this:
$( "#pages" ).sortable({
helper: "clone",
update: function(event, ui) {
console.log($(ui.item).attr("id"));
console.log($(ui.item).index() + 1);
}
});
This code returns the id and the position of the dragged object. But I also want to retrieve the other auto moved image id and new position so I can use that for my Database?
Instead use sort(event, ui) which will give you additional information such as the new and original positions of the sorted item. You can then iterate over your array, reassigning position indexes based on these values.
http://api.jqueryui.com/sortable/#event-sort
UPDATE
Apologies, it seems the API no longer includes the before and after indexes. Instead you can use both the start(event, ui) and stop(event, ui) events, and record down the before and after indexes yourself using $(ui.item).index(). After you know these, you can then iterate over your original array, sorted by index position, and update the indexes accordingly.
UPDATE 2
Try this:
$("#pages").sortable({
stop: function(event, ui) {
$("#pages > img").each(function(i, item) {
var id = $(this).attr("id");
array[id] = i;
});
});
});
UPDATE 3
The following revision caters for multiple items, initialised by the classname sort.
var array = { One : {}, Two: {} };
$(".sort").sortable({
stop: function(event, ui) {
var id = $(this).attr("id");
$(this).children().each(function(i, item) {
var itemid = $(item).attr("id");
array[id][itemid] = i;
});
console.log(array)
}
});
See my fiddle.

Get current index of jCarouselLite image/page

I've looked through the other questions about this and not found a suitable answer.
What I need is very simple: The index of the currently shown item.
Here's my little chunk of config
$('.carousel').jCarouselLite(
{
btnNext: "#right-navigation",
btnPrev: "#left-navigation",
visible: 1,
afterEnd: function(a)
{
// Code that requires the index
}
});
Note: the a is an object
Thanks!
The elements representing the items
that are visible after the animation
ends are passed in as argument.
so you should be able to do something like
afterEnd: function(a){
var index = $(a[0]).index();
}
to get the index of the first element

JQuery: How to cache DOM?

I used Firefug to profile my web application and found that the following function is called, and needs to be called, literally hundreds of times per user visit. So I want to optimize it since Firebug says it uses the most resources/times.
function highlightChildDiv(parentDiv) {
/* find the closest (hlisting) home listing to the middle of the scrollwindow & highlight */
var scrollElemPos = parentDiv.offset();
var highlightDiv = $(document.elementFromPoint(
scrollElemPos.left + parentDiv.width() / 2,
scrollElemPos.top + parentDiv.height() / 2)
).closest('#parentDiv div.childClass');
if (highlightDiv.hasClass("HighlightRow")) {
return; // if the div is already highlighted, return
} else {
$('#parentDiv div.childClass').removeClass("HighlightRow");
highlightDiv.addClass('HighlightRow');
}
}
Seems to me that one of the most un-optimized statements is .closest('#parentDiv div.childClass');, but I'm sure there is other things to improve.
Question: Does anyone have any JQuery performance tips on how I can optimize the code above given that this function is run literally hundreds of times per user visit.
First thought, eliminate the dead statement in the if clause.
if (!highlightDiv.hasClass("HighlightRow")) {
$('#parentDiv div.childClass').removeClass("HighlightRow");
highlightDiv.addClass('HighlightRow');
}
In the selector #parentDiv div.childClass, can you guarantee that div will be a direct descendent of #parentDiv? In which case:
.closest('#parentDiv>div.childClass');
and
$('#parentDiv>div.childClass')
You already have parentDiv. I'm guessing this is a DOM object, so you may be able to do the following:
$(parentDiv).children("div.childClass")
Just hide the DIV that is currently highlighted:
$('#parentDiv div.HighlightRow').removeClass("HighlightRow");
My guess is this is the most unoptimized line:
$('#parentDiv div.childClass').removeClass("HighlightRow");
You should profile it to make sure (create a date object outside the call and output the getTime() value before and after each call).
Here you are asking jQuery to iterate over all DOM elements that match that selector and remove the class. If there are 1000 rows, jQuery will need to interogate each one to see if it needs to remove a class. Ugh. Here it is with that lookup removed:
// namespace scoped cache
var Hash_$_Cache = {
$parentDiv : $('#parentDiv'),
$tgt_row : $([]) // empty jq object to start
};
// find the closest (hlisting) home listing to the middle of
// the scrollwindow and highlight
//
var highlightChildDiv = function (parentDiv){
var
scrollElemPos = parentDiv.offset(),
$tgt_row
;
$tgt_row = $(document.elementFromPoint(
scrollElemPos.left + parentDiv.width() / 2,
scrollElemPos.top + parentDiv.height() / 2)
).closest('#parentDiv div.childClass')
;
// bail if row is already highlighted
if ($tgt_row.hasClass('HighlightRow')){ return; }
Hash_$_Cache.$tgt_row.removeClass('HighlightRow');
$tgt_row.addClass('HighlightRow');
// save highlighted row for later
Hash_$_Cache.$tgt_row = $tgt_row; // store new row in cache
};
Hope that helps!
I prefer to use the following methodology:
https://gist.github.com/3841424#file-domcache-js
Or, you may replace the DOM object with a method in this implementation:
var myNS = {
myEventHandler: function(event){
this.DOM.$el.doSomething();
},
cacheDOM: function(){
return {
$el: $("#matrix")
};
},
initialize: function(){
this.DOM = this.cacheDOM();
}
};

Categories

Resources