Fancytree addNode function not working inside for loop - javascript

I want to move some nodes from one fancy tree to another based on a condition. So in a for loop, for every node I am checking the condition and add it to second fancy tree using addNode() function.
But inside the for loop addNode function is not working.
Here is my forloop code.
'toNodeID' is the id of the fancy tree to which nodes need to be moved. 'selectedValue' is some string value
$.each(selNodes, function (node, selNode) {
if (selNode != null) {
if (toNode.tree == $('#toNodeID').fancytree("getTree")) {
if (selNode.tooltip != selectedValue) {
toNode.addNode(node,'after);
}
}
}
});

You can use
toNode.addChildren(node);
to add a child node of toNode.

Related

Eloquent Javascript HELP NEWBIE

I'm having a lot of trouble figuring out how the recursive function is being done in this example. Problem is that he uses this technique farther down the book and I feel I need to have a grasp of what's he doing or I'm doomed. I've tried to console log the result of the function (part in quotes) to see how it changes down the line, but it doesn't give me a clear view of what's going on. Since returns often exit functions and loops, and the function is returning true at the end, I can't seem to track down how the function's suppose to work, let alone the recursive part
function talksAbout(node, string) {
if (node.nodeType == Node.ELEMENT_NODE) {
for (let child of node.childNodes) {
console.log(talksAbout(child,string));
if (talksAbout(child, string)) {
return true;
}
}
return false;
} else if (node.nodeType == Node.TEXT_NODE) {
return node.nodeValue.indexOf(string) > -1;
}
}
console.log(talksAbout(document.body, "book"));
// → true
From my best understanding of this, here's how it works, assuming the block of code is the talksAbout function.
if (node.nodeType == Node.ELEMENT_NODE) {
I'm guessing this is checking if the node it's looking at is an "element" that likely contains other nodes.
for (let child of node.childNodes) {
console.log(talksAbout(child,string));
if (talksAbout(child, string)) {
return true;
}
}
return false;
Here, the function seems to be iterating through the children of an element. Best I can explain it is, it's basically sending a "chain" of itself down the tree of an element, and if it finds something it's looking for, it returns true. If it doesn't find anything, it returns false.
} else if (node.nodeType == node.text_NODE) {
This is checking if the node it's looking at is a text node, which I'm assuming probably doesn't have any other children.
return node.nodeValue.indexOf(string) > -1;
}
Here, it's checking if the string in the "string" parameter exists inside the node. If it is, it returns true, and this "true" cascades down the line of recursive calls and eventually, the entire function returns true.
If it isn't, it just kinda... does nothing, letting the other calls in the "chain" check for other stuff.
EDIT:
It turns out, the function is massively overcomplicated. It isn't necessary to use a recursive function to search through all of the children: it's possible to just search through node.textContent and check for the string you're looking for. The recursive function is equivalent to this simplified function:
function talksAbout(node, string) {
return node.textContent.indexOf(string) > -1;
}
It also should be noted that if the <script> tag containing the function call is inside the node being searched, the function will always return true because it'll reach into the script tag and find the function's "string" parameter.
Example:
function talksAbout(node,string) {
return node.textContent.indexOf(string) > -1; // functionally equivalent to the recursive function
}
console.log("document.body talks about 'book': " + talksAbout(document.body, "book")); // This script tag is inside document.body, so it finds the "book" string here
console.log("wrapper talks about 'bar': " + talksAbout(document.getElementById("wrapper"), "bar")); // finds string in second layer
console.log("example talks about 'bar': " + talksAbout(document.getElementById("example"), "bar")); // the word "bar" comes before the element being searched
<div id="wrapper">foo
<div>bar
<div id="example">baz</div>
</div>
</div>

function to mirror insertAdjacentHTML

I am trying to write a function to mirror the insertAdjacentHTML dom method Element.insertAdjacentHTML and here it is
function insertAdjacent(targetElement) {
'use strict';
return {
insertAfter: function (newElement, targetElement) {
var parent = targetElement.parentNode;
if (parent.lastChild === targetElement) {
parent.appendChild(newElement);
} else {
parent.insertBefore(newElement, targetElement.nextSibling);
}
},
insertAtBegin: function (newElement) {
var fChild = targetElement.firstChild;
if (!fChild) {
targetElement.appendChild(newElement);
} else {
targetElement.insertBefore(newElement, fChild);
}
},
insertAtEnd: function (newElement) {
var lChild = targetElement.lastChild;
if (!lChild) {
targetElement.appendChild(newElement);
} else {
this.insertAfter(newElement, targetElement.lastChild);
}
}
};
}
The function works fine when you insert two different element nodes at the beginning and the end as shown here. But the problem comes when i try to insert the same element node at the beginning and the end as shown here. It only inserts the element node at the end and not at both the beginning and end.
What could be causing this issue? Thank you
Because One element can't be insert in two place at the same time, if you want to do it, at each function's first line, add newElement = newElement.cloneNode(true); I've altered your 2nd jsfiddle, have a look.
The problem was that you are using the exact same element, which can only be placed in one place...
If you clone it, there shouldn't be a problem.
Here's your second fiddle exactly as you have written it, with an extra deepCopy function from this answer:
adjacentInsert.insertAtBegin(deepCopy(span1));

GoJS delete child nodes without knowing parent node's key

I have a goJS diagram with a custom model. When dropping a node on another node, I link them when the mouseDrop fires and set the from and to in the link data on the diagram.model:
mydiagram.model.addLinkData({ from: oldNodeModel.key, to: dragNodeModel.key });
This all works fine. In my node template I have a custom template which puts a panel around the nodes with a delete button. This delete button is simply an image with a click event.
Now when I click the delete image/button, I want to delete this now and all its child nodes.
My issue is I cannot find the children.
I have user events like findNodesOutOf, which yields no results and findNodesConnected which finds parents and child nodes and deletes the lot - which is not what I want.
Any idea how I can solve this?
You can get the item to delete by using the diagram.selection:
var nodeToDelete = mydiagram.selection.iterator.first();
Next to find all the children of this node I recommend a recursive function which will do the following:
Take in the node you want to delete,
Find all the connected nodes to it using mydiagram.getChildrenNodes(nodeToDelete)
Itterrate through the cconnected nodes
Check if each node is a child, by using the linkNodeModel and checking is the link goes from the currentnode to the child node.
Then call the recursive function again with this child node
The recursive function will return an array with all child nodes
Then you can delete them.
Your code will look something like this:
function deleteNode()
{
// TAKE NOTE - This will get all selections so you need to handel this
// If you have multiple select enabled
var nodeToDelete = mydiagram.selection.iterator.first();
var childNodes = getChildNodes(deletedItem);
//Remove linked children
$.each(childNodes, function()
{
myDiagram.remove(this);
});
// Then also delete the actual node after the children was deleted
// TAKE NOTE - This will delete all selections so you need to handle this
// If you have multiple select enabled
mydiagram.commandHandler.deleteSelection();
}
The recursive function keeps checking each node for its children and adds them to an aray:
function getChildNodes(deleteNode)
{
var children = [];
var allConnected= deleteNode.findNodesConnected();
while (allConnected.next())
{
var child = allConnected.value;
// Check to see if this node is a child:
if (isChildNode(deleteNode, child))
{
// add the current child
children.push(child);
// Now call the recursive function again with the current child
// to get its sub children
var subChildren = getChildrenNodes(child);
// add all the children to the children array
$.each(subChildren, function()
{
children.push(this);
});
}
}
// return the children array
return children;
}
This function will check if the node is a child by looking at the links in the diagram and checking to to and from against the current node and child node:
function isChildNode(currNode, currChild)
{
var links = myDiagram.links.iterator;
while (links.next())
{
// Here simply look at the link to determine the direction by checking the direction against the currNode and the child node. If from is the current node and to the child node
// then you know its a vhild
var currentLinkModel = links.value.data;
if (currentLinkModel.from === currNode.data.key && currentLinkModel.to === currChild.data.key)
{
return true;
}
}
return false;
}

Function with memoization, how not to evaluate each time?

I'm writing a simple jQuery function that will swap some HTML elements for others when on certain viewports. The idea is simple:
<div data-swap-for="#element" data-swap-on="phone"></div>
Will insert the element with id #element after that line when the current media query corresponds to phone (the details about how that is done are not important).
My function looks like this:
jq.fn.swapElements = function(viewport) {
var targets = jq('[data-swap-for][data-swap-on='+viewport+']');
if (targets.length) {
console.log('Found elements to swap for', viewport);
} else {
console.log('Found no elements to swap for', viewport);
}
return {
on: function() {
console.log('Should swap elements for', viewport);
},
off: function() {
console.log('Should restore elements', viewport);
}
}
};
So whenever the screen enters the phone layout, it calls:
jq().swapElements('phone').on();
Which should do all the DOM transformations, and when it exits the phone layout, it calls:
jq().swapElements('phone').off();
Which should restore them.
My problem is that these two are creating a new evaluation of the var targets... part, resulting in:
As the output in the console, and I need this function to cache or remember the variables that it uses, so that the resulting console output is:
> Found elements to swap for phone
> Should swap elements for phone
That is, only evaluating the elements and saving the variables once per each call (a different viewport value should call for a new evaluation).
I've been looking into higher order functions and memoization, but I'm confused about how to apply this in this case and specially to a jQuery function.
Please help?
Thanks
You can use some variable (object or array) to cache already targeted elements.
var cache = {}; // Should be out of function
if (viewport in cache) {
var targets = cache[viewport];
} else {
var targets = jq('[data-swap-for][data-swap-on='+viewport+']');
cache[viewport] = targets;
}
I Would go with slightly different approach:
jq.fn.swapElements = {
var cache;
getTargets: function(viewport) {
if (viewport in this.cache) {
return cache[viewport];
} else {
var targets = jq('[data-swap-for][data-swap-on='+viewport+']');
if (targets.length) {
console.log('Found elements to swap for', viewport);
} else {
console.log('Found no elements to swap for', viewport);
}
this.cache[viewport] = targets;
return this.cache[viewport];
}
}
on: function(viewport) {
console.log('Should swap elements for', viewport);
},
off: function(viewport) {
console.log('Should restore elements', viewport);
}
};
Pseudocode might not work in particular case, but You get the idea. Whenever You need targets you call swapElements.getTargets(viewport) function.
I'm pretty sure you don't need a higher-order memoize function (although you could trivially apply it when you have written one anyway).
What you need to do is to store the result of jq().swapElements('phone') in a variable, and when the screen enters/exits the phone layout you should call the methods on that variable, instead of creating new instances.

PHPJS' array_diff returns undefined

Example:
http://jsfiddle.net/7Cwbn/60/
I'm trying to use array_diff function from PHPJS to check if all of the elements inside selectedFeatures are found inside elem.features, but instead I receive undefined. What gives?
$(markers.houses).each(function(index, elem) {
//first filter by selected features
console.log(array_diff(elem.features, selectedFeatures).length);
if (array_diff(selectedFeatures, elem.features).length == 0) {
if (!markers.houseMarkers[index].visible) {
markers.houseMarkers[index].setVisible(true);
}
}
});
Solution:
Inside array_diff() definition change the retVal to equal [] instead of {}.

Categories

Resources