I am struggling with logic on how to make dynamic breadcrumbs.
I have nested array of objects, and when a user clicks a folder, it adds to the breadcrumbs.
However, currently clicking 2 folders in the same folder adds both folders to the breadcrumbs rather than adding the last clicked folder.
Furthermore, clicking a folder thats deep within the folder tree will not show all previous folders it has passed.
All in all, I just need the logic for breadcrumbs, in javascript.
My attempt is as follows:
Folders.json
[
{
"name": "Documents",
"files": [
{
"name": "Quarterly Results"
}
]
},
{
"name": "Favourites",
"files": [
{
"name": "Brawl Stars",
"files": [
{
"name": "NS dying in 5 seconds"
},
{
"name": "Josiah raping NS"
}
]
},
{
"name": "Coding",
"files": [
{
"name": "Coding is so fun"
},
{
"name": "I love svelte",
"files": [
{
"name": "REPL"
},
{
"name": "oh nooo"
}
]
}
]
},
{
"name": "Favourites 1"
},
{
"name": "Favourites 2"
},
{
"name": "Favourites 3"
}
]
},
{
"name": "Knowledge Base 1"
}
]
Sidebar.svelte
<script>
export let currentFolder
export let currentFolderFlow
export let expanded = false;
export let name;
export let files;
const sideBarFolder = (folderName) => {
if (currentFolder === folderName) {
return false
}
currentFolder = folderName
if (!currentFolderFlow.includes(folderName)) {
currentFolderFlow = [...currentFolderFlow, folderName]
} else {
currentFolderFlow = currentFolderFlow.filter(i => currentFolderFlow.indexOf(i) <= currentFolderFlow.indexOf(folderName))
}
}
</script>
<button class=" pl-1" on:click={() => sideBarFolder(name)}>{name}</button>
Main
<script>
import TreeView from './side-bar.svelte'
let currentFolderFlow = ['Knowledge Base']
let currentFolder = 'Knowledge Base'
</script>
<!-- Breadcrumbs -->
<div class="flex-1 px-3">
<div class="text-md breadcrumbs border rounded-lg p-3">
<ul id="breadcrumbs">
{#each currentFolderFlow as folderFlow}
<li>{folderFlow}</li>
{/each}
</ul>
</div>
</div>
Just a folder name is not enough, for sure. e.g. if you have structure like abc / def / abc, you are in folder def and click on its child abc, it will crop to the root abc folder.
There are different ways to solve it.
Create some kind of unique ID for each folder and pass it. Thus, you'll have to scan for it each time, which will take much time.
Have a parent property in each folder, which will link to the parent object. And pass the folder object instead of its name.
You can pass an array of names: sideBarFolder(["Favourites", "Coding", "I love svelte"]). But to get the array, you'll have to use method 1 or 2 anyway, probably.
Related
I am trying to export nested json to excel with specific format in react. I found few solution with XLSX which print only root node but I would also like to print nested nodes. Here is my JSON
[
{
"Root":"00000",
"RootId":"b597b7be58b0",
"Index":0,
"Child":[
{
"ChildId":"48bb0b4be689",
"Name":"Dimension",
"Index":0,
"SubChild0":[
{
"SubChildId":"6b620696cf35",
"Label":"Sample 2",
"Index":1
},
{
"SubChildId1":"f6b620696cf38",
"Label":"Sample 2",
"Index":2
}
]
},
{
"ChildId-01":"dcf70d3a-60b3-4b8c-8740-48bb0b4be689",
"Name":"Weight",
"Index":0,
"SubChild1":[
{
"SubChildId":"f42d99f5-37c5-4ea3-8425-6b620696cf35",
"Label":"Sample 2",
"Index":1
},
{
"SubChildId1":"f42d99f5-37c5-4ea3-8425-6b620696cf35",
"Label":"Sample 2",
"Index":2
}
]
}
]
}
]
and I would like to print in excel something like below format
I've never used any libraries that would help with your problem so cannot suggest any.
Your source data can be processed using javascript.
Your data almost fits a regular nested list with children, so creating a recursive function to process the data into something that can be interpreted as a CSV shouldn't be too difficult.
Your data has different tags so is a little more complicated.
The example below wont work for your data as-is. But it might give you an idea of where to start?
// source data with uniform keys in child objects
let data = [
{
"name": "root1",
"label": "root label",
"children": [
{
"name": "root1child1",
"label": "root1 child1 label",
"children": [
{
"name": "root1child1subchild1",
"label": "root1 child1 subchild1 label"
},
{
"name": "root1child1subchild2",
"label": "root1 child1 subchild2 label"
}
]
},
{
"name": "root1child2",
"label": "my label",
"children": [
{
"name": "root1child2subchild1",
"label": "root1 child2 subchild1 label"
},
{
"name": "root1child2subchild2",
"label": "root1 child2 subchild2 label"
}
]
}
]
}
]
let result = []
function process(node,padding) {
for (let i = 0, l = node.length; i<l; i++) {
result.push(Array(padding).concat("name", node[i].name))
result.push(Array(padding).concat("label", node[i].label))
if (node[i].children) {
// process the child node and pad the result to the right
process(node[i].children,++padding)
}
// reset padding and continue with next
--padding
}
}
// start processing the data
process(data,0)
// print the result as a table to the console
console.table(result)
How to render images, if i get path from json file. Default i use require('../assets/img/item-image.png'). But i have no idea, how use it in this case
Component:
<div v-for="(item, index) in items">
<img :src="item.src">
</div>
<script>
import axios from 'axios'
export default {
name: 'componentName',
data () {
return {
items: null
}
},
mounted () {
axios
.get('./test.json')
.then(response => (this.items = response.data))
}
}
</script>
JSON file:
[
{
"id": 1,
"title": "item title",
"src": "../assets/img/item-image.png",
"alt": "item-image",
"text": "item body"
}
]
You need to keep using require() in order to let Webpack know to include your images when bundling.
Because Webpack bundles at compile time and your images are only known at runtime, this is best done by keeping part of the path static so Webpack can optimistically include the right files.
For example, if all your images are under ../assets/img, the best option would look like this
async mounted () {
const pathRegex = /^\.\.\/assets\/img\//
const { data } = await axios.get("./test.json")
this.items = data.map(item => ({
...item,
src: require(`../assets/img/${item.src.replace(pathRegex, "")}`)
}))
}
Webpack will then bundle every file under ../assets/img and at runtime, will be able to resolve the paths you supply.
See https://webpack.js.org/guides/dependency-management/#require-with-expression
You must add require
<img :src="require(item.src)">
This was how I solved it. I kept getting an error when using the regex above to add require to the src attribute in the json. This is what I did instead and it worked for me.
I am using fetch() to read the json which I am watching with json-server. The json is basically an array (cokeImages) of objects when you use res.json() to convert it.
{
"cokeImages": [
{
"title": "Cocacola Life",
"description": "Lorem ipsum no sicut anon in aquila no ager. In homines ad majorem tempus avis, et cum in pecunia imoten tua",
"src": "../assets/cocacola-cans/cocacola-life.png",
"id": 1,
"name": "cocacola-life",
"nutrition": [
{ "title": "sodium", "value": "150 cl", "percent": "25%" },
{ "title": "Total Fats", "value": "0g", "percent" : "0%" },
{ "title": "sodium (mg)", "value": "40mg", "percent": "0%"},
{ "title": "potasium", "value": "4g", "percent": "0%" },
{ "title": "calcium", "value": "0g", "percent": "0%"}
]
},
{
"title": "Cocacola Zero",
"description": "Lorem ipsum no sicut anon in aquila no ager. In homines ad majorem tempus avis, et cum in pecunia imoten tua",
"src": "../assets/cocacola-cans/cocacola-zero.png",
"id": 2,
"name": "cocacola-zero",
... (and so on)...
as you can see, the name property in each object is also the name I used in each images src.
It is that name property I used in the map() method to attach require to each src.
mounted(){
fetch("http://localhost:3000/cokeImages")
.then(response => response.json())
.then(arrayOfOjects => {
console.log(arrayOfObjects)
this.cokeImages = data.map(eachObject => {
return {...eachObject, src: require(`../assets/cocacola-cans/${eachObject.name}.png`)}
})
console.log(this.cokeImages)
})
.catch(err => {
console.log(err.message)
})
}
I'm quite new to Vue.js. I'm used to vanilla JavaScript.
I need to be able to generate route paths from a JSON file.
How can I achieve it?
EDIT
For example, say this is my JSON:
[
{
"name": "Product 1",
"url": "product-1",
},
{
"name": "Product 2",
"url": "product-2",
}
]
I basically need Vue Router to redirect URL/product-1 to Product 1's component (which will be <Product-1></Product-1>), and URL/product-2 to Product 2's component (<Product-2></Product-2>)
Assuming your component's name is name in the object, we need to match your structure to Vue Router API.
Thus, we can do as follows:
const myRoutes = [
{
"name": "Product 1",
"url": "product-1",
},
{
"name": "Product 2",
"url": "product-2",
}
]
const router = new VueRouter({
routes: myRouters
.map(({name, url})=>({component: name, path: `/${url}`)),
})
I have a nested object displayed in my view and i want to search in it from the query like this :
http://localhost:3000/test?$folder=folder
My object is like this :
const test = {
"item": [
{
"name": "folder",
"item": [{
"name": "subFolder",
"item": [
{
"name": "subFolderTest1",
"item": [{
"path": "/",
"items": [{
"method": "GET",
}]
}]
},
{
"name": "subFolderTest2",
"item": [{
"path": "/",
"items": [{
"method": "GET",
}]
}]
}
]
}]
}
]
}
If i have http://localhost:3000/test?$folder=folder then i would have :
{
{
"name": "subFolder",
"item": [{},{}]
}
}
And if i have http://localhost:3000/test?$folder=folder/subFolder then i will have :
{
{
"name": "subFolderTest1",
"item": [{}]
},
{
"name": "subFolderTest2",
"item": [{}]
}
}
I know how to get what's inside my query and what the user's input but i don't how to search and display from something which is already displayed.
If you already have your query string you could split it by the "/" character. Use the first name to find your first item, the second name to find the second, and so on.
var folder = "folder/subFolder";
var path = folder.split("/");
var currentItem = test["item"];
// Get each name you are looking for
path.forEach(function(name) {
// get each entry of the current item
currentItem.forEach(function(entry) {
// if the name of the entry is the same as the
// name you are looking for then this is the
// next item you are looking for
if (entry.name == name) {
currentItem = entry["item"];
}
});
});
// now currentItem should be the entry specified by your path
You will still have to add code to handle situations like not having the name you are looking for in your current item, or having multiple entries with the correct name, and so on. I just kept it simple for the sake of clarity.
I have an object array which look something like below,
{
"data": [
{
"name": "HTML",
"description": "Hyper Text Markup Language"
},
{
"name": "CSS",
"description": "Cascading Style Sheet"
},
{
"name": "JS",
"description": "Javascript"
}
]
}
I get the above object array as a response from this end point /get/technologies, suppose if this end point is gonna have a query string some thing like this /get/technologies?q=CSS how can i filter the response just to render the below,
{
"data": [
{
"name": "CSS",
"description": "Cascading Style Sheet"
}
]
}
I have a node/express app so in the controller if i do "req.query.q" then i can grab the query parameter, with that query parameter how can i filter the original object array.. i came across some npm packages but not sure which would suite my need,
https://www.npmjs.com/package/filter-array
https://www.npmjs.com/package/object-filter
https://www.npmjs.com/package/array-filter
https://www.npmjs.com/package/array-query
It would also be nice if i can grab the query parameter and find the matching texts.. say for example if the query parameter is just "SS" then the result should render both CSS and JS since the text "S" is there in both of them.
Working Example
Try this:
var d = [
{
"name": "HTML",
"description": "Hyper Text Markup Language"
},
{
"name": "CSS",
"description": "Cascading Style Sheet"
},
{
"name": "JS",
"description": "Javascript"
}
];
var a = d.filter(function(el) {
return el.name === 'CSS';
});
You could just use filter:
var data = [
// the array to be filtered
];
var filteredArray = data.filter(item => (item.name === req.query.q));