I am creating a formulary and some fields are intended to occupy just 50% of the size that a normal field would take.
It is a dynamic formulary so i use a v-for that take a form object from vuex and use its data to summon the correct component on screen.
I em using because i have TextField's, DateField's, CheckField's and all this configuration is made in the forms object.
Now, to the code:
At store/module/forms.js (vuex) (it is a list of objects like this one):
[
{
name: 'familiarIncome',
type: 'TextField',
value: '',
options: {
dataname: 'familiarIncome',
mandatory: true,
label: 'Renda familiar',
placeholder: '',
rules: fieldRules.float('a renda familiar'),
css: 'width: 50%', // Attention here. This will be injected into component
},
}
]
Then, at pages/formulario.js: (note that until now i wrote only 3 input components)
<template>
<v-app class="container d-flex justify-center">
<h1>Coleta de dados</h1>
<v-form class="container fluid">
<h2>Dados pessoais</h2>
<div class="personal-data d-flex flex-wrap">
<div
v-for="field in getForm.personalData"
:key="field.name"
class="field"
<!-- Pay attention to this class up here (field) -->
>
<component
:is="field.type"
<!-- Here is where all those options -including "width: 50%" are being injected -->
v-bind="field.options"
#change="updateData((section = 'personalData'), $event)"
></component>
</div>
</div>
<div class="social-benefits"></div>
<div class="is-disabled"></div>
<div class="address"></div>
<div class="child-already-born"></div>
</v-form>
</v-app>
</template>
<script>
import { mapGetters } from 'vuex'
import TextField from '../components/inputs/textfield.vue'
import ConfirmButton from '../components/inputs/confirmbutton.vue'
import SelectField from '../components/inputs/selectfield.vue'
export default {
name: 'Formulario',
components: { TextField, ConfirmButton, SelectField },
data() {
return {
formToken: this.$route.params.token,
}
},
computed: {
...mapGetters(['getForm']),
},
methods: {
updateData(section, eventData) {
const data = {
section,
...eventData,
}
this.$store.commit('setFormField', data)
console.log(this.$store.state)
},
},
}
</script>
<style scoped>
.field {
padding: 7px;
width: 50%;
}
h1 {
font-size: 36px;
}
h2 {
font-size: 24px;
}
</style>
And now a print of the web page:
If i missed any important info, please let me know ;)
(just for the case where someone complains, i searched A LOT before asking here ;) )
Ok so i figured it out some minutes later by trying to do things that would look wrong (great technique by the way)
What i did was taking out the wrapping div arount the <component> tag, so then the 50% width would really take the right effect.
Related
I can't change style in ant-tooltip on nuxtjs. I access to class ant-tooltip-inner but it don't changing.
<div class="box-form-input">
<a-tooltip placement="topRight" trigger="focus">
<template slot="title">
<span>Please fill in your Fullname</span>
</template>
<a-input
v-model="full_name"
/>
</a-tooltip>
</div>
<style>
.ant-tooltip-inner {
background-color: red;
}
</style>
Overriding Antd tooltip in vue.js works as expected.
<template>
<div id="app">
<!-- remove h3 tag causes wrong arrow direction -->
<h3>try to remove this element.
<br>After removed, the tooltip arrow changed direction.
</h3>
<a-tooltip placement="left" title="wrong arrow direction">
<span>why don't use popper.js</span>
</a-tooltip>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld
}
};
</script>
<style>
.ant-tooltip-inner {
background-color: red;
}
</style>
See working CodeSandBox.
I created a form component Form.vue which is a child from PostPage.vue.
Inside 'Form.vue' i want to send a $emit for the parent to change a Prop value btn-text.
Parent Component PostPage.vue:
<template>
<div id="post-page">
<div class="header-text pt-5 text-center">
<div class="h2 font-weight-bold">
Welcome to the DevTribe Community
</div>
<div class="h5 font-weight-bold">
Ask questions, share content, introduce yourself. Be nice!
</div>
</div>
<Form />
<!-- textarea-not-clear isn't catched here below -->
<Posts
:btn-text="btnText"
#textarea-not-clear="changeBtnText()"
/>
</div>
</template>
<script>
import Form from './PostPage/Form.vue';
import Posts from './PostPage/Posts.vue';
export default {
name: 'PostPage',
components: {
Form,
Posts
},
data() {
return {
}
},
methods: {
changeBtnText() {
console.log('tss');
}
}
}
</script>
<style lang="scss" scoped>
#post-page {
background-color: #ffffff;
height: 100%;
padding: 0 20%;
}
</style>
The emit will be fired in a watch, if the textarea is empty
Child Component Form.vue:
<template>
<div id="form">
<form class="text-area text-center mt-5 mx-auto w-100">
<div class="row">
<div class="col-12">
<textarea
v-model="textarea"
name="post-text"
rows="6"
class="w-100"
placeholder="Create a post..."
/>
</div>
<div class="col text-left">
<button
type="button"
class="btn btn-outline-primary"
>
Send
</button>
</div>
</div>
</form>
</div>
</template>
<script>
export default {
name: 'Form',
data() {
return {
textarea: ''
}
},
watch: {
textarea: function() {
if (this.textarea !== '') {
this.$emit('textarea-not-clear', 'Join Discussion');
}
}
}
}
</script>
<style lang="scss" scoped>
.text-area {
height: 300px;
textarea {
border: solid black 1px;
}
button {
width: 120px;
}
}
</style>
I can see the event fired in Vue extension for DevTool:
but for some reason it is not possible to catch that event, the changeBtnText() function inside PostPage.vue won't be triggered and gives not even a console.log('test')
First things first. Form is not a good name for a component as it clashes with a standard HTML element. I'm surprised you aren't getting a warning about this. See https://v2.vuejs.org/v2/style-guide/#Multi-word-component-names-essential
Next up, the problem with your event is that you're listening to the wrong component.
<Form />
<!-- textarea-not-clear isn't catched here below -->
<Posts
:btn-text="btnText"
#textarea-not-clear="changeBtnText()"
/>
The event is being fired by the Form component but your listener is on the Posts component.
I would also highly recommend that you stop using ids on your components and uses classes for styling instead.
I'm writing a Vue component, which accepts 2 slots:
<template>
<div class="Component">
<div class="Component-Label">
<slot
name="label"
class="Component-LabelInner"
/>
</div>
<div class="Component-Input">
<slot
name="input"
class="Component-InputInner"
/>
</div>
</div>
</template>
<style scoped>
.Component { ... }
.Component-Label { ... }
.Component-LabelInner { ... }
.Component-Input { ... }
.Component-InputInner { width: 100%; ... }
</style>
For layout purposes, I absolutely need to apply some styles to the <slot> elements - the ones with Component-LabelInner and Component-InputInner classes.
(To be precise I need to apply a rule width: 100% to the Component-InputInner, as usually I'll pass there <input> element and I want everything I pass there to stretch to the container.)
The problem is that after <slot> elements get replaced by the content provided to the slots, class attribute isn't inherited (it seems no attributes are inherited on slots) and CSS selectors for .Component-LabelInner and .Component-InputInner don't work.
Can you somehow add CSS classes to the element that <slot> gets replaced with?
You can not bind class to slot tag. There are some solutions to handle this case:
With Vue mounted hook (it works but looks as bad practice):
Vue.component("slots-comp", {
template: "#slotsCompTemplate",
mounted() {
// each slot is an array, because you can pass a set of nodes wrap them with template tag
// I use only first VNode for example
this.$slots.one && this.$slots.one[0].elm.classList.add("one");
this.$slots.two && this.$slots.two[0].elm.classList.add("two");
}
});
new Vue({
el: "#app",
data: {}
})
.one {
color: red
}
.two {
color: blue
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<slots-comp>
<div slot="one">One</div>
<div slot="two">Two</div>
</slots-comp>
</div>
<script type="text/x-template" id="slotsCompTemplate">
<div>
<slot name="one"></slot>
<slot name="two"></slot>
</div>
</script>
Pass neccessary classes as props to scoped slot(it is not fully encapsulated solution):
Vue.component("slots-comp", {
template: "#slotsCompTemplate",
data() {
return {
classes: {
one: ["one"],
two: ["two"]
}
}
}
});
new Vue({
el: "#app",
data: {}
})
.one {
color: red
}
.two {
color: blue
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<slots-comp>
<div slot-scope="props" :class="props.classes.one" slot="one">One</div>
<div slot-scope="props" :class="props.classes.two" slot="two">Two</div>
</slots-comp>
</div>
<script type="text/x-template" id="slotsCompTemplate">
<div>
<slot :classes="classes" name="one"></slot>
<slot :classes="classes" name="two"></slot>
</div>
</script>
Add changes to CSS to apply styles on all internal elements:
.Component-Input > *
{
/* my rules for child elements */
}
.Component-Label> *
{
/* my rules for child elements */
}
Or add wrapper element for slots with classes Component-InputInner etc. and add similar styles for them.
Hope it will help.
I am working on a perfect-scrollbar directive.
yarn add perfect-scrollbar
I found this lying around, but it silently fails.
This is the code:
<template>
<div class="scroll-area">
<img src="https://i.kinja-img.com/gawker-media/image/upload/s--I5-_uX-9--/c_scale,fl_progressive,q_80,w_800/oh1cxyrtivnead6tn8k6.png" v-scroll/>
</div>
</template>
<script>
import { Container, PerfectScrollbar } from 'myCompnts';
export default {
name: 'Test',
data() {
return {
};
},
directives: {
scroll: PerfectScrollbar
},
components: {
Container
},
};
</script>
<style scoped>
.scroll-area {
position: relative;
width: 100px;
height: 300px;
overflow: hidden;
}
</style>
Unfortunately, it either "no element is specified to initialize PerfectScrollbar", or it gives back these cryptic error messages suggesting an issue with compilation:
Just as the element was not passed in correctly. Vue Chrome debugger provides no info on whether the directive actually got there. The idea sounds sexy as hell, but how to implement it? Thanks for any help, really! :)
Disclaimer: I have tried to read the docs before opening this question.
I have this component:
<template>
<accordion id="facilities-menu" :one-at-atime="true">
<template v-for="facilities in facilitiesGroups">
<panel class="accordion-toggle" :header="`Facilities #${$index+1}`" :is-open="$index === 0">
<ul>
<li v-for="facility in facilities">
{{facility}}
</li>
</ul>
</panel>
</template>
</accordion>
</template>
<style lang="scss" scoped>
#import "../../../styles/theme-colors.scss";
.panel {
background: #5E6466;
border: none;
}
</style>
<script>
import { accordion, panel } from 'vue-strap'
module.exports = {
components: {
accordion, panel
},
data () {
return {
'facilitiesGroups': [['Continente Alfragide', 'Jumbo Almada', 'Portugália'], ['Pingo Doce', 'Lidl', 'Allegro'], ['Casa']]
}
}
}
</script>
And then I instantiate this component like this:
<template>
<div class="user">
<user></user>
</div>
<facilities></facilities>
</template>
<style lang="scss" scoped>
#import "../../../styles/theme-colors";
.user {
width: 100%;
height: auto;
margin-top: 8%;
margin-bottom: 5%;
}
</style>
<script>
import User from './userProfile'
import Facilities from './groupedFacilities'
module.exports = {
components: {
'user': User,
'facilities': Facilities
}
}
</script>
However, you can see that in the first component I am defining the data to be { 'facilitiesGroups': [['Continente Alfragide', 'Jumbo Almada', 'Portugália'], ['Pingo Doce', 'Lidl', 'Allegro'], ['Casa']] }. But i want this to be passed as an argument, not to be statically defined in the component as it is now.
I have read the docs about how could this be done here. But their example...
Vue.component('child', {
// declare the props
props: ['msg'],
// the prop can be used inside templates, and will also
// be set as `this.msg`
template: '<span>{{ msg }}</span>'
})
...Resembles nothing to what I have in my code... I don't even use Vue.component() anywhere!
How come I am using a different "style" of coding with Vue JS (I started from their boilerplate)?
How can I map Vue JS official documentation to this "style"?
How can pass that array as an argument/property?
Thanks!
Your component needs to declare the data you want passed in as 'props'
<script>
import { accordion, panel } from 'vue-strap'
module.exports = {
components: {
accordion, panel
},
props: ['facilitiesGroups']
}
</script>
... then in your parent component template you pass your data as an attribute. Below is an example where "facilitiesGroups" is a data element of your parent component:
<template>
<div class="user">
<user></user>
</div>
<facilities :facilities-groups="facilitiesGroups"></facilities>
</template>