JavaScript: How to re-index multidimensional object after deleting a nested object? - javascript

I need to delete a nested object based on index and i and then re-index the object. I am using Vuejs, so this is in the methods. However, this code doesn't work the way I intended it to. The main issue is deleting this.realTagFilters[0][0] will also delete this.realTagFilters[1][0] and this.realTagFilters[2][0] and so on. It will also occasionally not correctly index the index or i but I have not found the cause of that issue yet. Overall, this code is pretty buggy and I could use some outside perspective on how to properly create this function.
Edit: I am using an npm package for searchable multi-select selection lists that only allow objects to be passed to the options attribute.
Here is the script:
export default {
props: {
tag_filters: Object
},
data() {
return {
tagfilters: {
0: {
0: {
code: {
code: 'Thank You Codes'
},
condition: {
condition: 'AND'
}
},
}
}
}
}
computed: {
realTagFilters() {
if (Object.keys(this.tag_filters).length > 0 && typeof Object.keys(this.tag_filters) !== 'undefined') {
return this.tag_filters['filter'];
} else {
return this.tagfilters;
}
}
},
method: {
deleteFilter(index, i){
delete this.realTagFilters[index][i];
for(var property in this.realTagFilters) {
for (var p in this.realTagFilters[property]) {
if(property > index && p > i) {
property -= 1;
this.realTagFilters[property] = this.realTagFilters[property + 1];
delete this.realTagFilters[property + 1];
if(p > i) {
p -= 1;
this.realTagFilters[property][p] = this.realTagFilters[property][p + 1];
delete this.realTagFilters[property][p + 1];
}
}
else if (property == index && p > i) {
p -= 1;
this.realTagFilters[property][p] = this.realTagFilters[property][p + 1];
delete this.realTagFilters[property][p + 1];
}
}
}
if(Object.keys(this.realTagFilters[index]).length == 0) {
delete this.realTagFilters[index];
}
this.$forceUpdate();
},
}
}

You could try Vue's delete function in favor of javascript's delete keyword, so instead of doing delete this.realTagFilters[index][i] you'd do:
this.$delete(this.realTagFilters[index], i);
Another trick to let Vue know data has changed is to replace your object with a new object, like so:
// after you've done your operations:
this.realTagFilters = {...this.realTagFilters};
The last option is this.$forceUpdate() which you are already doing.

Related

node_modules select2 replace wrappedMatcher with startMatcher

I'm trying to change the select2.julll.js file from node_modules Angular 6 project.
So far I found some ways to do that tho, nothing has worked for me, would you fave any suggestions of how I can replace wrappedMatcher with startMatcher in select2 file?
S2.define('select2/compat/matcher',[
'jquery'
], function ($) {
function oldMatcher (matcher) {
function wrappedMatcher (params, data) {
var match = $.extend(true, {}, data);
if (params.term == null || $.trim(params.term) === '') {
return match;
}
if (data.children) {
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
// Check if the child object matches
// The old matcher returned a boolean true or false
var doesMatch = matcher(params.term, child.text, child);
// If the child didn't match, pop it off
if (!doesMatch) {
match.children.splice(c, 1);
}
}
if (match.children.length > 0) {
return match;
}
}
if (matcher(params.term, data.text, data)) {
return match;
}
return null;
}
return wrappedMatcher;
}
return oldMatcher;
});
Adding the following code to my select2.directives.ts has solved my problem
if (data.text.toString().toLowerCase().indexOf(params.term) > -1 &&
!!data.text.toString().toLowerCase().startsWith(params.term.toString().toLowerCase())) {
var modifiedData = $.extend({}, data, true);
// modifiedData.text += ' (matched)';
// You can return modified objects from here
// This includes matching the `children` how you want in nested data sets
return modifiedData;
}

Javascript Recursion returning undefined

I'm struggling in a recursive Javascript function to find a specific subdirectory. This is my code:
function navigateToParent() {
var parentFullPath = parentDirectory(); // gets the full Path String
if (parentFullPath != null) {
var parent = getDirectoryByName(parentFullPath, rootDirectory);
// set the parent directory object as the current one
currentDirectory(parent);
}
}
function getDirectoryByName(fullName, myDirectory) {
if (myDirectory.fullName == fullName) {
return myDirectory;
} else {
var subs = myDirectory.subDirectories;
for (i = 0; i < subs.length; i++) {
return getDirectoryByName(fullName,subs[i]);
}
}
}
Every directory object has the properties fullName(string),subDirectories(array of directories) and files(array of files). My aim is to get the correct directory object, where it's fullName is matching.
I know, that i have to break the for loop in some way, but i don't know how to do it exactly.
After overthinking the logic i came to this solution (seems to work):
function getDirectoryByName(fullName, myDirectory) {
if (myDirectory.fullName == fullName) {
return myDirectory;
} else {
var subs = myDirectory.subDirectories;
for (i = 0; i < subs.length; i++) {
var match = getDirectoryByName(fullName, subs[i]);
if (typeof match !== "undefined"){
return match;
}
}
}
}

Need help iterating through a complex Json (no jquery)

I need to create a symfony2 bundle that generates a sidebar from a YAML file
I created this YAML structure
Sidebar:
- Frontpage:
- Dashboard:
_icon: 'icon-home'
_route: 'link'
- Actions:
- My_Likes:
_icon: 'icon-dislike'
_route: 'link'
- My_Dislikes:
_icon: 'icon-home'
_route: 'link'
- Interests:
- Add_Interest:
_icon: 'icon-home'
_route: 'link'
which returns this JSON as a response.
{
"Sidebar": [
{
"Frontpage": [
{
"Dashboard": {
"_icon": "icon-home",
"_route": "link"
}
}
]
},
{
"Actions": [
{
"My_Likes": {
"_icon": "icon-dislike",
"_route": "link"
}
},
{
"My_Dislikes": {
"_icon": "icon-home",
"_route": "link"
}
}
]
},
{
"Interests": [
{
"Add_Interest": {
"_icon": "icon-home",
"_route": "link"
}
}
]
}
]
}
Using ajax, the json is returned on the 'data' variable on the client side
Sidebar.model.request(function(data)
{
for(var a=0; a< data.Sidebar.length; a++ )
{
console.log(data.Sidebar[a]);
}
});
I need to find a way to iterate through the parents and find the corresponding children.
I only need help creating the for loop, so a solution using console.log(data[stuff]); would be enough
EDIT:
here is the adjusted snippet of Daniel Rosano's code
Sidebar.model.request(function(data)
{
//Get Sidebar items
var SidebarItems = data.Sidebar;
//Find Categories in Sidebar Items
for(var a=0; a< SidebarItems.length; a++ )
{
var category = SidebarItems[a];
//Get Category name and append it to sidebar
var category_name = getSubitemName(category);
Sidebar.view.renderCategory(category_name);
//find subitems in categories
for(var b=0; b < category[category_name].length; b++)
{
var button = category[category_name][b];
var button_name = getSubitemName(button);
var button_attributes = button[button_name];
console.log(button_attributes['_icon']);
Sidebar.view.renderButton(button_name);
}
}
function getSubitemName(parent)
{
for(child in parent)
{
return child.toString();
}
}
});
this is the result, thanks Daniel
I know you've already accepted an answer, but I had already written this and then got distracted before posting so I thought I'd share it anyway.
It's a recursive iterator that walks through any arrays or objects it finds in whatever you pass in. It also keeps track of the "path" down to any particular item and the level (mostly for illustrative purposes, but it could be otherwise useful too). A general purpose iterator that would work for any data passed in, pretty much has to be recursive to handle arbitrary depth.
function iterate(item, path, level) {
level = level || 0;
path = path || "root";
if (typeof item === "object") {
if (Array.isArray(item)) {
out("iterating array: " + path, level);
for (var i = 0; i < item.length; i++) {
iterate(item[i], path + "[" + i + "]", level + 1);
}
} else {
out("iterating object: " + path, level);
for (var prop in item) {
// skip any properties on the prototype
if (item.hasOwnProperty(prop)) {
iterate(item[prop], path + "." + prop, level + 1);
}
}
}
} else {
// leaf level property
out(path + " = " + item, level);
}
}
Working demo to see how the path and level work: http://jsfiddle.net/jfriend00/k8aosv59/
Not sure if this is what you need
for (var a = 0; a < t.Sidebar.length; a++) {
var children = t.Sidebar[a];
for (k in children) {
var subchild = children[k];
for (m in subchild) {
var sschild = subchild[m];
for (n in sschild) {
// menu variable has the inner childs (having "_icon" and "_route")
var menu = sschild[n];
console.log(menu._icon+ " "+menu._route);
}
}
}
}
Hope it helps
Dan
You can do it recursively:
function iterate(obj) {
console.log(obj);
for (var key in obj) {
var items = obj[key];
for(var i=0,l=items.length;i<l;i++) {
iterate(items[i]);
}
}
}
iterate(data);
Fiddle

can't change image position with javascript function

I did some code to change my image position
This code can run once , but doesn't work second time.
function prev() {
if(document.getElementById("bookCon").style.left=="0px"){}
else {
document.getElementById("bookCon").style.right-="800px";
}
}
function next() {
if(document.getElementById("bookCon").style.left=="5000px") {}
else {
document.getElementById("bookCon").style.right+="800px";
}
}
second edition ... also not work.
function getStyleNum(item,prop) {
if (typeof item == "string") { item = document.getElementById(item); }
return parseInt(item.style[prop],10);
}
function prev() {
var item = document.getElementById("bookCon");
if (getStyleNum(item,"right") !== 0) {
var val = getStyleNum(item, "right");
item.style.right = (val - 800) + "px";
}
}
function next() {
var item = document.getElementById("bookCon");
if (getStyleNum(item,"right") !== 1600) {
var val = getStyleNum(item, "right");
item.style.right = (val + 800) + "px";
}
}
There are multiple issues with your code:
You can't do += "800px" because you will end up with something like "500px800px" as these are strings.
You can't do math on strings.
You can't reliably compare to "0px"
You check the value of .left and set the value of .right. You should only be using one or the other, not both.
Your code could a lot more DRY (not repeating things)
Reading the style property directly on the object won't include anything set via style sheets
If the style.left value is directly set on the object (and not initially coming from a style sheet) and your object is positioned, then you can use this type of logic (converting to numbers). I don't know exactly what you're trying to accomplish by checking .left and then changing .right so this is just a guess at your logic, but you should be able to see the general idea of how you do this sort of thing.
function prev() {
var item = document.getElementById("bookCon");
if (parseInt(item.style.left, 10) != 0) {
var val = parseInt(item.style.right, 10) || 0;
item.style.right = (val - 800) + "px";
}
}
You may find this util function useful:
function getStyleNum(item, prop) {
if (typeof item == "string") {
item = document.getElementById(item);
}
return parseInt(item.style[prop], 10) || 0;
}
function prev() {
var item = document.getElementById("bookCon");
if (getStyleNum(item, "left") != 0) {
var val = getStyleNum(item, "right");
item.style.right = (val - 800) + "px";
}
}
P.S. I still don't understand why you would check the value of .left and then modify the value of .right. Only one of these can be active at a given time.
Working demo: http://jsfiddle.net/jfriend00/awjv9/

superslides jquery plugin customization

Hi All,
I need help customizing this jquery plugin so that the pagination looks like links with text in them instead of like the default.
So basically the output on the page should be: Link1 | Link2 | Link3,etc. I have tried creating an Array and returning that Array to the addPaginationItem() function, however, all attempts have been very unsuccessful.
Any help would be much appreciated as I have been struggling with it.
2 main functions Code that I need to manipulate looks as follows:
addPaginationItem = function(i) {
if (!(i >= 0)) {
i = _this.size() - 1;
}
return $pagination.append($("<a>", {
href: "#" + i,
"class": _this.current === $pagination.children().length ? "current" : void 0
}));
};
addPagination = function() {
var array, last_index;
if (!_this.options.pagination || _this.size() === 1) {
return;
}
if ($(el).find("." + _this.options.classes.pagination).length) {
last_index = $pagination.children().last().index();
array = $children;
} else {
last_index = 0;
array = new Array(_this.size() - last_index);
$pagination = $pagination.appendTo(_this.el);
}
return $.each(array, function(i) {
return addPaginationItem(i);
});
};
Thanks
I have solved my own problem. I think I just needed to walk away from the code for a bit.
Thanks all. I added the following code which solved my problem
addPaginationItem = function(i,linkText) {
if (!(i >= 0)) {
i = _this.size() - 1;
}
return $pagination.append($("<a>", {
href: "#" + i,
text:linkText,
"class": _this.current === $pagination.children().length ? "current" : void 0
}));
};
addPagination = function() {
var array, last_index;
var hrefText = ['test1','test2','test3','test4'];
if (!_this.options.pagination || _this.size() === 1) {
return;
}
if ($(el).find("." + _this.options.classes.pagination).length) {
last_index = $pagination.children().last().index();
array = $children;
} else {
last_index = 0;
array = new Array(_this.size() - last_index);
$pagination = $pagination.appendTo(_this.el);
}
$.each(hrefText,function(intIndex,objValue) {
linkText = objValue;
return addPaginationItem(intIndex,linkText)
});
};

Categories

Resources