VueJS and Ant Design - update input fields - javascript

I am really new to Vue.js and have a question.
What I want to achieve is:
-Have two input fields. If you type in something in the first input field, the value of the second input field should be updated with the value of the first input but base64 encoded.
Here is what I have tried:
main.js:
import Vue from 'vue';
import App from './App';
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
Vue.use(Antd);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
data: {
tokenInput: null,
tokenOutput: null,
},
methods: {
handleChange: function() {
this.tokenOutput = btoa(this.tokenInput);
}
}
}).$mount('#app');
App.vue:
<template>
<div id="app">
<Home/>
</div>
</template>
<script>
import Home from './components/Home.vue'
export default {
name: 'App',
components: {
Home
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
Home.vue:
<template>
<div>
<h1>helloworld</h1>
<a-tabs default-active-key="1">
<a-tab-pane key="1" tab="token converter">
<div class="content">
<a-card title="Input" class="token">
<a-textarea
v-model="tokenInput"
#change="handleChange"
allowClear
placeholder="Input the token to convert ..."
:rows="20"
>
</a-textarea>
</a-card>
<a-card title="Converted token:" class="token">
<a-textarea
:value="convertedToken"
disabled
:rows="20"
/>
</a-card>
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="2nd tab"> Nothing is here. </a-tab-pane>
</a-tabs>
</div>
</template>
<style>
.content {
padding: 24px;
}
.token {
margin: 10px;
padding: 10px;
width: 100%;
}
</style>
The error message I get:
Property or method "handleChange" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property
I have also tried:
new Vue({
render: h => h(App),
data() {
return {
tokenInput: null,
tokenOutput: null,
}
},
methods: {
handleChange() {
this.tokenOutput = btoa(this.tokenInput);
}
}
}).$mount('#app');
What am I doing wrong ?

Related

pass emit click to parent in slot element to run function in parent vue 3 slot option api

greeting king,
I'm trying to emit click from child(todoitem.vue) element that contains button and slot in this component to parent(app.vue) that will run a method in parent. For example now when I click edit button then method in parent editable() will run and when I click delete button then run method of deletable() in parent. How to approach this. I had tried to pass using v-slot but it only send variable also try emit but failed to emit. I'm totally new to vue..thanks
parent(app.vue)
<template>
<div>
<todolist>
<todoitem v-for="each in a" :key="each.list">
{{each.list}}
</todoitem>
</todolist>
<todolist>
<todoitem v-for="each in b" :key="each.list">
{{each.list}}
</todoitem>
</todolist>
</div>
</template>
<script>
import todolist from "./components/todolist.vue";
import todoitem from "./components/todoitem.vue";
export default {
name: "App",
data(){
return{
a:[
{list:"AAAA"},
{list:"BBBB"},
{list:"CCC"},
],
b:[
{list:"DDDD"},
{list:"EEEE"},
{list:"FFFF"},
],
}
},
components: {
todolist,
todoitem
},
methods:{
editable(){
console.log('editabel')
},
deletable(){
console.log('deletable')
}
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
child(todoitem)
<template>
<slot></slot>
<button #click="test">Edit</button>
<button #click="test2">delete</button>
</template>
<script>
export default {
name: "todoitem",
method:{
test(){
console.log('edit click')
this.$emit('edit-item')
},
test2(){
console.log('delete click')
this.$emit('del-item')
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
todolist
<template>
<slot></slot>
<div>
</div>
</template>
<script>
export default {
name: "todolist",
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
Basically it's structured like this - just put an emit with the function-name and the paramters inside of one of your methods like this:
Child.vue
this.$emit("Your_Function_Name", Parameter_1, Parameter_2);
Than go to your parent.vue call your emitted function and use it inside your methods of the parent.vue:
Parent.vue
<template>
...
<Child #Your_Function_Name="Your_Function_Name">
...
</template>
<script>
methods: {
Your_Function_Name(Parameter_1, Parameter_2) {
console.log(Parameter_1, Parameter_2)
}
}
</script>
Hopefully this helps you out!

How to style a <slot> from child component Vue.js 3.x

I am trying to style a p tag that is slotted into a child component using the tag.
Parent Code
<template>
<BasicButton content="Test 1234" #click="SendMessage('test')" height="10" width="50" />
<TransparentTopbar />
<BasicContainer width="90">
<p class="p-blueish-gray">{{ LorumIpsum() }}</p>
</BasicContainer>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Homepage from "./components/home/Homepage.vue";
import TransparentTopbar from "./components/tools/topbar/TransparentTopbar.vue";
import BasicButton from "./components/tools/button/BasicButton.vue";
import BasicContainer from "./components/tools/container/basic_container/BasicContainer.vue"
//import func from "vue-temp/vue-editor-bridge";
export default defineComponent({
name: "App",
components: {
Homepage,
TransparentTopbar,
BasicButton,
BasicContainer
},
methods: {
SendMessage: sendMessage,
LorumIpsum: lorumIpsum
},
});
Child Code
<template>
<div class="light-rounded-container card-margins" :style="container_style">
<slot></slot>
</div>
</template>
<script lang="ts" src="./BasicContainer.ts" />
<style scoped src="./BasicContainer.css" />
import { defineComponent } from 'vue';
export default defineComponent({
name: 'BasicContainer',
props: {
width: {
type: Number,
default: 90,
required: false
}
},
data() {
return {
container_style: {
width: this.width.toString() + '%'
}
}
},
methods: {}
});
.light-rounded-container {
background-color: #242629;
border-radius: 15px;
align-self: center;
}
::v-slotted(p) {
color:red !important;
width: 1% !important;
padding-left: 5% !important;
padding-right: 5% !important;
padding-top: 25px !important;
padding-bottom: 15px !important;
}
The BasicContainer component is the one I am trying to style slotted content on. I would like to style the p tag that I pass to this component in the parent, but I would like to style it from within this child component.
#StevenB. you are corrent. I did not have my style in a separately defined NON-SCOPED .css file. After moving my styling into their and re structuring my HTML to avoid bleeding the css style into other global scope, it worked. Much appreciated.

Property or method "names" is not defined on the instance but referenced during render

i'm creating a CRUD using vuejs and Firebase, but I don't know how to fix this error,
[Vue warn]: Property or method "names" is not defined on the instance but referenced during render.
So I can add information to the real time database, however, I can not show the data inside the database tables to my Vuejs application.
someone can help me?
this is my firebase.js
import firebase from 'firebase';
const firebaseConfig = {
apiKey: "AIzaSyBDWnEjj0OJayCxR4kJl4iDn9LocDGVcw8",
authDomain: "operand-teste-front-end.firebaseapp.com",
databaseURL: "https://operand-teste-front-end.firebaseio.com",
projectId: "operand-teste-front-end",
storageBucket: "operand-teste-front-end.appspot.com",
messagingSenderId: "648371507080",
appId: "1:648371507080:web:6030b3583a933b69e2b43d",
measurementId: "G-RN0RCH48Y4"
}
const firebaseApp = firebase.initializeApp(firebaseConfig)
export const db = firebaseApp.database()
export const namesRef = db.ref('names');
export const jobRefs = db.ref('jobs')
main.js
import Vue from 'vue'
import App from './App.vue'
import './Firebase'
import { firestorePlugin } from 'vuefire'
Vue.use(firestorePlugin)
new Vue({
el: '#app',
render: h => h(App)
})
App.vue
<template>
<div id="app">
<div>
CRUD usando VUEJS + Firebase
<hr>
<div class="formulario">
<label>
Nome:
</label>
<input type="text" v-model="nome"/>
<br>
<label>
Profissão:
</label>
<input type="text" v-model="job" />
<br>
<button #click="addPessoa">
Adicionar
</button>
</div>
</div>
<div>
<ul>
<li v-for="personName in names" :key="personName['.key']">
{{personName}}
</li>
</ul>
</div>
</div>
</template>
<script>
import {jobRefs,namesRef} from './Firebase'
export default {
data () {
return {
nome: '',
job: ''
}
},
firebase:{
names:namesRef
},
methods: {
addPessoa(){
namesRef.push({nome: this.nome, edit: false})
jobRefs.push({job: this.job, edit: false})
}
}
}
</script>
<style>
#app {
font-family: Arial, Helvetica, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
.formulario{
width: 170px;
border: 3px aqua solid;
margin: 20px auto;
background-color: rgb(102, 201, 255);
}
button{
border: 2px;
background-color: transparent;
}
</style>
Expected Result: Data saved to Firebase is rendered on the view
Reality:
[Vue warn]: Property or method "names" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
It will help me a lot to solve this problem.
I hope my mother tongue doesn't get in the way.
You've installed the Cloud Firestore plugin but you're trying to use the Realtime Database.
Use this instead in your main.js file
import { rtdbPlugin } from "vuefire"
Vue.use(rtdbPlugin)
See https://vuefire.vuejs.org/vuefire/getting-started.html#plugin
You also need to import the Firebase database component. In your firebase.js script...
import firebase from "firebase/app"
import "firebase/database"
See https://firebase.google.com/docs/web/setup#using-module-bundlers

Problem nesting Vue components within components

I can nest components within the root App.vue component just fine but if I try and nest a component within a non root component nothing shows up. If I instead nest the Navbar component that wont show up in Splash.vue within App.vue it works, likewise if I move the Footer component to Splash.vue it doesn't.
App.vue (Footer component works fine, router then loads splash.vue)
<template>
<div id="app">
<Footer/>
<router-view/>
</div>
</template>
<script>
import Footer from '#/components/Footer'
export default {
name: 'App',
components: {
Footer
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 0px;
}
</style>
Splash.vue (Navbar component doesnt load, the text does load so I know the router is working correctly)
<template>
<div class="test">
<v-container fluid>
<Navbar/>
<p>splash loaded</p>
</v-container>
</div>
</template>
<script>
import Navbar from '#/components/layout/Navbar'
export default {
name: 'Splash',
data () {
return {
components: {
Navbar
}
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.landing-card-style {
border-radius: 4px;
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14);
}
</style>
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
Vue.use(Vuetify)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(App)
})
Navbar.vue
<template>
<div class="navbar">
<nav class = "deep-purple">
<div class="container">
<h1>navbar component loaded</h1>
</div>
</nav>
</div>
</template>
<script>
export default {
name: 'Navbar',
data(){
return{
}
}
}
</script>
<style>
</style>
You have your components inside data() function.
Try this instead:
export default {
name: 'Splash',
components: {
Navbar
}
}

Access the $refs of a parent from a child - Vue.js

Hopefully this has been answered before - essentially I'm trying to append a block ("CodeBlock.vue") to an element inside App.vue from an onClick event triggered inside a sibling of CodeBlock, and a child of App.vue, ("ButtonSidebar.vue"). I'm a little confused by emitting events and/or using an eventBus Vue instance, so any pointers would be greatly appreciated:
So far I have the following. CodeBlock.vue which will be used as an instance and appended to a div inside App.vue.
CodeBlock.vue:
<template>
<div :class="type">
THIS IS A CODE BLOCK!!
</div>
</template>
<script>
export default {
name: 'CodeBlock',
props: [ 'type' ]
}
</script>
App.vue:
<template>
<div id="app" class="container">
<ButtonSidebar/>
<div id="pageBlocks" ref="container"></div>
</div>
</template>
<script>
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'
// import { eventBus } from './main'
import AddTitle from './components/modules/AddTitle'
import AddSubTitle from './components/modules/AddSubTitle'
import ButtonSidebar from './components/modules/ButtonSidebar'
import CodeBlock from './components/modules/CodeBlock'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
export default {
name: 'App',
components: {
AddTitle,
AddSubTitle,
ButtonSidebar,
CodeBlock
}
}
</script>
<style>
#app {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #1f1f1f;
margin-top: 60px;
}
.no-border {
border: unset !important;
border: 0px !important;
}
</style>
ButtonSidebar.vue:
<template>
<div>
<b-button class="btn-circle absolute-float-tight text-dark" v-on:click="reveal=!reveal">
<font-awesome-icon v-if="!reveal" :icon="faPlusIcon" />
<font-awesome-icon v-if="reveal" :icon="faMinusIcon" />
</b-button>
<transition name="custom-classes-transition" enter-active-class="animated bounceInDown" leave-active-class="animated bounceOutRight">
<div v-if="reveal" class="absolute-float-reveal">
<b-button class="btn-circle text-dark" v-on:click="addCodeBlock"><font-awesome-icon :icon="faCodeIcon" /></b-button>
</div>
</transition>
</div>
</template>
<script>
import Vue from 'vue'
import FontAwesomeIcon from '#fortawesome/vue-fontawesome'
import faPlus from '#fortawesome/fontawesome-pro-regular/faPlus'
import faMinus from '#fortawesome/fontawesome-pro-regular/faMinus'
import faCode from '#fortawesome/fontawesome-pro-regular/faCode'
import CodeBlock from './CodeBlock'
export default {
name: 'ButtonSidebar',
computed: {
faPlusIcon () {
return faPlus
},
faMinusIcon () {
return faMinus
},
faCodeIcon () {
return faCode
}
},
components: {
FontAwesomeIcon,
CodeBlock
},
data () {
return {
reveal: false
}
},
props: ['codeBlocks'],
methods: {
addCodeBlock () {
var ComponentClass = Vue.extend(CodeBlock)
var instance = new ComponentClass({
propsData: { type: 'primary' }
})
instance.$mount()
this.$el.querySelector('#pageBlocks').appendChild(instance.$el)
}
}
}
</script>
<style scoped>
.absolute-float-tight {
left: 20px;
position: absolute;
}
.absolute-float-reveal {
left: 60px;
position: absolute;
}
.btn-circle {
background-color: transparent;
border-radius: 50%;
height: 34px;
padding: 0;
width: 34px;
}
</style>
It's around the this.$el.querySelector('#pageBlocks').appendChild(instance.$el) part that I start to loose the plot a bit...I'm worried that I have to strip everything down and start again perhaps?
You should avoid reaching to the DOM as much as possible. The source of truth for the data should be in your components.
refs are very useful to integrate other js library that needs a DOM element.
So in your case, assuming codeBlocks are available in your App.vue components, the SidebarButton needs to emit an event when it's clicked so that the parent App.vue can add a new Codeblock:
(I have removed some code not needed for the example. CodeBlock.vue stays the same)
App.vue
<template>
<div id="app" class="container">
<ButtonSidebar #add-block="addCodeBlock" />
<CodeBlock v-for="block in codeBlocks" :type="block.type" />
</div>
</template>
<script>
import ButtonSidebar from '../ButtonSidebar'
import CodeBlock from '../CodeBlock'
export default {
name: 'App',
components: {ButtonSidebar, CodeBlock},
data() {
return {
codeBlocks: []
}
},
methods: {
addCodeBlock() {
const newBlock = {type: 'whatever'}
this.codeBlocks.push(newBlock)
}
}
}
</script>
ButtonSideBar.vue
<template>
<div>
<b-button class="btn-circle text-dark" v-on:click="addCodeBlock</b-button>
</div>
</template>
<script>
export default {
name: 'ButtonSidebar',
data () {
return {
reveal: false
}
},
methods: {
addCodeBlock () {
this.$emit('add-block')
}
}
}
</script>
A good pattern to follow in Vue is to lift the state to the parents and passing it down as props whenever you feel like you want to share state between parents and children.
I think you could achieve it in this simple way:
App.vue (template section)
<ButtonSidebar #add="addCodeItem"/>
<div id="pageBlocks">
<codeBlock v-for="code in arrCodes" :type="code.type"/>
</div>
App.vue (script)
export default {
data() {
return {
arrCodes: []
}
},
methods: {
addCodeItem(codeType) {
this.arrCodes.push( { type: codeType } )
}
}
}
ButtonSidebar.vue (script section)
addCodeBlock () {
this.$emit('add', 'yourtype');
}

Categories