I want to build a mindmapping tool using Vue.
I found this vue3-mindmap component. The issue I'm facing is it that it's not dynamically updating the mindmap when I update the underlying data. I think the issue is it uses a clone of the modelValue to build the mindmap and hence it's not reactive.
#App.Vue
<template>
<mindmap v-model="state.data"
:edit=true
:add-node-btn=true></mindmap>
<div >{{ state }} </div>
<button #click="updateData">Update Data</button>
</template>
<script>
import { reactive} from 'vue'
import mindmap from 'vue3-mindmap'
import 'vue3-mindmap/dist/style.css'
export default {
components: { mindmap },
setup() {
const state =reactive({data:[{ 'name': 'Old Data' }]})
function updateData() {
state.data=[{ 'name': 'New Data' }]
}
return {state,updateData}
}
}
</script>
I have little understanding of JS libraries and I'm struggling to fix the source code and use it in my project. Any help would be appreciated.
You are right, the modelValue is getting internally copied to a new ImData object.
emitter.emit('mmdata', new ImData(cloneDeep(props.modelValue[0]), xGap, yGap, getSize))
I haven't found any simple way to manipulate the internal data outside of the Mindmap plugin. There is already the issue After the v-model binding data is updated, the brain map page is not updated accordingly (Chinese) about the problem.
Workaround
If it does now work other way, you can always use the following ugly workaround.
You can force Vue to destroy the mindmap using v-if and recreate it again from scratch.
Here is the sample how to achieve it
<script setup>
import { ref, nextTick } from 'vue'
import mindmap from 'vue3-mindmap'
const data = ref([{ 'name': 'Old Data' }])
function updateData() {
data.value = [];
nextTick(() => {
data.value = [{ 'name': 'New Data' }];
})
}
</script>
<template>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/vue3-mindmap#0.5.12/dist/style.css" media="screen" />
<mindmap v-if="data.length > 0" v-model="data" :edit=true :add-node-btn=true></mindmap>
<div >{{ data }} </div>
<button #click="updateData">Update Data</button>
</template>
And the working playground
Related
I am learning Meteor and I created a test app and added accounts-ui and accounts-password packages, then I inserted {{>loginButtons}} into main.html. However all I got on the page was an empty . I didn't see any errors in the console either. Is the widget broken, or am I missing something? In all tutorials I saw it was just working with no other action required, so I'm confused. I am using Blaze. Also, is Meteor a good choice of framework for building a social media app, or should I use something else?
I installed older version (14.22.1) of node.js as it's what Meteor recommends, I also installed accounts-google package instead of accounts-password to see if that one works, and it worked fine.
Main.js and Main.html
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Accounts } from 'meteor/accounts-base';
import './main.html';
Template.hello.onCreated(function helloOnCreated() {
// counter starts at 0
this.counter = new ReactiveVar(0);
});
Template.hello.helpers({
counter() {
return Template.instance().counter.get();
},
});
Template.hello.events({
'click button'(event, instance) {
// increment the counter when button is clicked
instance.counter.set(instance.counter.get() + 1);
},
});
Accounts.ui.config({
passwordSignupFields: 'USERNAME_AND_OPTIONAL_EMAIL'
});
<head>
<title>Test</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
<nav class="main-nav">
<a>Test Link 1</a>
<a>Test Link 2</a>
<a>Test Link 3</a>
{{> loginButtons}}
<a>Test Link 4</a>
</nav>
{{> hello}}
{{> info}}
</body>
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
</template>
<template name="info">
<h2>Learn Meteor!</h2>
<ul>
<li>Do the Tutorial</li>
<li>Follow the Guide</li>
<li>Read the Docs</li>
<li>Discussions</li>
</ul>
</template>
I am creating list of items looped through .map function. I want each of these items be rendered in a single page with some other details.
import React from 'react'
import {faArrowRight, faMusic, faPlay, faPlayCircle, faTachometerAlt} from "#fortawesome/free-solid-svg-icons";
import {FontAwesomeIcon} from "#fortawesome/react-fontawesome";
import music from '../mocks/music.json'
import { Link } from 'gatsby'
import Music from '../pages/music'
const newData = music.map( (data) => {
return (
<div className="row no-gutters justify-content-between align-items-center">
<div className="col-auto">
<button className="btn-gradient btn-circle">
<FontAwesomeIcon icon={faPlayCircle} />
</button>
</div>
<div className="col">
<div className="music-list-content">
<span className="artist">{data.author}</span>
<Link to={`/music/${data.id}`}>{data.title}</Link>
<span className="play">
<FontAwesomeIcon icon={faPlay} /> {data.duration}
</span>
</div>
</div>
<div className="col-auto">
<span className="badge-dark badge">{data.genre}</span>
</div>
</div>
)
})
const membersToRender = music.filter(member => member.id)
const numRows = membersToRender.length
const Musics = () => {
return (
<div>
<div className="title">
<h5>New Music</h5>
<span>{numRows} new songs</span>
</div>
<div>
<div className="music-list card-wrapper">
{newData}
</div>
</div>
<div className="footer-wrapper">
<div>
<FontAwesomeIcon icon={faMusic} />
<span>Song Library</span>
</div>
<FontAwesomeIcon icon={faArrowRight} />
</div>
</div>
)
}
export default Musics
I created a link which whenever I click, it takes me to another page (page not found) with id appended and .js extension.
Please, how do go about it? I want a click on the title and have it displayed on a full page.
Your logic seems good, however, you are missing the most important part, the page creation, since you are not creating the pages, all of your links are broken.
In Gatsby, you have two different ways of creating pages:
Using gatsby-node.js to create pages dynamically: when dealing with a huge amount of data, like your JSON, it's easier to let Gatsby deal with this responsibility of creating pages for Gatsby. Since you are sourcing from a JSON, you need everything set to create dynamic pages.
const path = require("path")
// Implement the Gatsby API “createPages”. This is called once the
// data layer is bootstrapped to let plugins create pages from data.
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const musics= require("./data/mocks/musics.json")
const musicTemplate = path.resolve(`src/templates/music-template.js`)
musics.forEach(music) => {
createPage({
path: `/music/${music.slug}`
component: musicTemplate,
context: {
title: music.title,
description: music.description,
// and so on for the rest of the fields
},
})
})
}
Note: I'm assuming that your JSON is properly defined and formatted, having all the fields I queried.
Your musicTemplate must be a template (inside /templates folder).
Notice that you are passing some fields through Gatsby's context, this means that those fields will be available through props.pageContext in your template. So, there, create a template like:
import React from "react"
import Layout from "../components/layout"
export default function MusicTemplate({pageContext}) {
return (
<Layout>
<div>Hello musician {pageContext.title}</div>
</Layout>
)
}
So, as I said, with this approach you are creating dynamic pages based on your JSON file, and they will be available inside localhost:8000/music/{music.slug}, and all your reference and links that point there, will be valid.
I would also recommend using static query/useStaticQuery to retrieve data from your JSON in that loop. If you create a static query from that data (in a separate component) you will be able to fetch it on-demand across your project, so you will be reusing an interesting part of logic. It's better to use it rather than requesting a JSON directly.
You can follow this guide from the great Jason Lengstorf which is mostly what you need.
Adding .js files in your /pages folder: Gatsby infers the internal structure of your /pages folder and will create pages accordingly to that structure. For instance, if you have a structure like: /pages/musicians/name1.js Gatsby will create a page like localhost:8000/musicians/name1.
As it has been said, the first approach fits your requirements and it's preferred for this use-cases, since the second one will be less scalable and maintainable.
You should do some routing with React-Router (https://reactrouter.com/web/example/basic).
So the link have to point to a Route in a Switch, as is in the example of the link.
I am trying to embed an aws quick sight dashboard on an angular app.
I am following the below URL to implement on Angular
https://github.com/awslabs/amazon-quicksight-embedding-sdk
Could you please help me with sample code on how to implement the below logic in Angular
<!DOCTYPE html>
<html>
<head>
<title>Basic Embed</title>
<script src="https://unpkg.com/amazon-quicksight-embedding-sdk#1.0.3/dist/quicksight-embedding-js-sdk.min.js" />
<script type="text/javascript">
var dashboard
function onDashboardLoad(payload) {
console.log("Do something when the dashboard is fully loaded.");
}
function onError(payload) {
console.log("Do something when the dashboard fails loading");
}
function embedDashboard() {
var containerDiv = document.getElementById("dashboardContainer");
var options = {
url: "https://us-east-1.quicksight.aws.amazon.com/sn/dashboards/dashboardId?isauthcode=true&identityprovider=quicksight&code=authcode",
container: containerDiv,
parameters: {
country: "United States"
},
scrolling: "no",
height: "700px",
width: "1000px"
};
dashboard = QuickSightEmbedding.embedDashboard(options);
dashboard.on("error", onError);
dashboard.on("load", onDashboardLoad);
}
function onCountryChange(obj) {
dashboard.setParameters({country: obj.value});
}
</script>
</head>
<body onload="embedDashboard()">
<span>
<label for="country">Country</label>
<select id="country" name="country" onchange="onCountryChange(this)">
<option value="United States">United States</option>
<option value="Mexico">Mexico</option>
<option value="Canada">Canada</option>
</select>
</span>
<div id="dashboardContainer"></div>
</body>
</html>
I am getting compile time error while importing embedDashboard module
import {embedDashboard} from 'amazon-quicksight-embedding-sdk/src';
ERROR in ./node_modules/amazon-quicksight-embedding-sdk/src/embedDashboard.js 6:12
Module parse failed: Unexpected token (6:12)
You may need an appropriate loader to handle this file type.
|
| import EmbeddableDashboard from './EmbeddableDashboard';
import type {EmbeddingOptions} from './lib/types';
|
How do I implement the above logic through angular? When I am trying to import QuickSightEmbedding for using the embedDashboard(options). I am getting compile time error.
If it is going to work at all, your import statement should look like this: import QuickSightEmbedding from 'amazon-quicksight-embedding-sdk'.
I am new to vue.js and currently I am building an app for learning purposes.
What I want to do:
I have a parent component which has a bunch of buttons with different id's.
The child component will wait for those id's to be sent by the parent and it will decide what to display based on the id. Thats all.
I wont post the full code because it's too large but I have tried a bunch of stuff like props and state but honestly it is so confusing.
I come from React background and I am still confused.
Parent component
<template>
<button id="btn1">Show banana</button>
<button id="btn2">Show orange</button>
</template>
<script>
export default {
name: 'Parent',
data: function {
//something
},
props: {
// ?????
}
};
</script>
**Child component**
<template>
<p v-html="something.text">
</template>
<script>
export default {
name: 'Child',
data: function() {
something: ''
if(id from parent === id I want) {
something = object.withpropIneed
}
},
};
</script>
You need to map the data from parent and pass it to child, thats it!
In example i make passing a html string and binding that html received through 'fromParentHtml' prop mapped on child, so inside child component 'this.fromParentHtml' pass to exists because it is defined in props and every time you click in parent button executes the 'show' function and change the value from passed prop to child through parent 'html' data .. =)
<template>
<div>
Current html sent to child '{{html}}'
<br>
<button #click="show('banana')">Banana</button>
<button #click="show('orange')">Orange</button>
<button #click="show('apple')">Apple</button>
<!-- Create child component -->
<child-component :fromParentHtml="html"></child-component>
</div>
</template>
<script>
export default {
name: "test3",
components: {
'child-component': {
template: "<div>Child component... <br> <span v-html='fromParentHtml'></span> </div>",
//Child component map a prop to receive the sent html from parent through the attribute :fromParentHtml ...
props: {
fromParentHtml: {
required: true,
type: String
}
}
}
},
data(){
return {
html: ''
}
},
methods: {
show(fruit){
this.html = '<span>The fruit is ' + fruit + ' !</span>';
}
}
}
</script>
<style scoped>
</style>
If helped you please mark as correct answer! Hope it helps.
Edit 1:
Assuming you have webpack to work with single file components, to import another component just do:
<template>
<div>
<my-child-component></my-child-component>
</div>
</template>
<script>
//Import some component from a .vue file
import ChildComponent from "./ChildComponent.vue";
export default {
components: {
//And pass it to your component components data, identified by 'my-child-component' in the template tag, just it.
'my-child-component': ChildComponent
},
data(){
},
methods: {
}
}
</script>
Just for the sake of it, I think you were looking for this:
<template>
<button id="btn1" #click = "id = 1">Show banana</button>
<button id="btn2" #click = "id = 2">Show orange</button>
<child-component :childid = "id"></child-component>
</template>
<script>
import childComponent from 'childComponent'
export default {
name: 'Parent',
data () {
return {
id: 0
}
},
components: {
childComponent
}
};
</script>
**Child component**
<template>
<p v-html="something.text">
</template>
<script>
export default {
name: 'Child',
props: {
childid: String
},
data: function() {
something: ''
if(this.childid === whatever) {
something = object.withpropIneed
}
},
};
</script>
Solved my problem by taking a different approach.
I have implemented state and my component behaves exactly as I wanted to.
I found this link to be helpful for me and solved my problem.
Thank you.
I am new to VueJS and I am confused why a simple example from the docs is not working for me.
This is all the code. I am expecting it to display "Howdie Partners" on the page.
HTML
<div id="app">
<greeting></greeting>
</div>
JS
Vue.component('greeting', {
template: '<h1>{{message}}</h1>',
props: ['message']
});
var vm = new Vue({
el: '#app',
data: {
message: "Howdie Partners!"
}
});
JSFiddle Link: https://jsfiddle.net/hq1yu0ct/
From the documentation:
we can also use v-bind for dynamically binding props to data on the parent. Whenever the data is updated in the parent, it will also flow down to the child.
So you need to pass the props in the greeting component like following:
<div id="app">
<greeting :message="message"></greeting>
</div>
check working fiddle here.