My view blade, you can see this below :
...
<div class="panel-body">
<order-view v-cloak>
<input slot="from-date" data-date-format="DD-MM-YYYY" title="DD-MM-YYYY" type="text" class="form-control" placeholder="Date" name="from_date" id="datetimepicker" required>
<input slot="to-date" data-date-format="DD-MM-YYYY" title="DD-MM-YYYY" type="text" class="form-control" placeholder="Date" name="to_date" id="datetimepicker" required>
</order-view>
</div>
...
My order-view component, you can see this below :
<template>
<div>
<div class="col-sm-2">
<div class="form-group">
<slot name="from-date" required v-model="fromDate"></slot>
</div>
</div>
<div class="col-sm-1">
<div class="form-group" style="text-align: center">
-
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<slot name="to-date" required v-model="toDate"></slot>
</div>
</div>
<div class="col-sm-4">
<button v-on:click="filter()" class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</div>
</div>
</template>
<script>
export default {
data() {
return{
fromDate: '',
toDate: ''
}
},
methods: {
filter: function() {
console.log(this.fromDate)
console.log(this.toDate)
}
}
}
</script>
I using v-model like above code
But, when I click the button, the result of
console.log(this.fromDate)
console.log(this.toDate)
is empty
It display empty
Why it does not work?
How can I solve it?
You cannot bind a slot using v-model and expect that Vue will attach that automatically to your slot input, but I can't see any reason why you need to use a slot here anyway. It looks like you just want an input that you can attach custom attributes to and you can do that by passing the attributes as a prop and use v-bind to bind them:
<template>
<div>
<input v-bind="attrs" v-model="fromDate" />
<button #click="filter">filter</button>
</div>
</template>
export default{
props: ['attrs'],
methods: {
filter() {
console.log(this.fromDate)
}
},
data() {
return {
fromDate: ""
}
}
}
new Vue({
el: "#app",
data: {
fromDateAttrs: {
'data-date-format': "DD-MM-YYYY",
title: "DD-MM-YYYY",
type: "text",
class: "form-control",
placeholder: "Date",
name: "from_date",
id: "datetimepicker",
}
}
});
Now you can just pass your attrs as a prop in the parent:
<my-comp :attrs="fromDateAttrs"></my-comp>
Here's the JSFiddle: https://jsfiddle.net/rvederzc/
EDIT
In reference as to how to create a date picker component, here's how I would implement a jQuery datepicker using Vue.js:
<template id="date-picker">
<div>
<input v-bind="attrs" v-model="date" #input="$emit('input', $event.target.value)" v-date-picker/>
</div>
</template>
<script type="text/javascript">
export default {
props: ['attrs'],
directives: {
datePicker: {
bind(el, binding, vnode) {
$(el).datepicker({
onSelect: function(val) {
// directive talk for 'this.$emit'
vnode.context.$emit('input', val);
}
});
}
}
}
}
</script>
You can then bind that with v-model in the parent:
<date-picker v-model="myDate"></date-picker>
Here's the JSFiddle: https://jsfiddle.net/g64drpg6/
Cant expect any javascript technology to be complete before it becomes famous. Going by that, I tried all the recommendations from using moment to vue-datapicker. All recommendations heavily broke design and needed hardcode of the div id's in the vue initialisation under mounted. Cant introduce hacks into my project this way. Messes up design and implementation neatness.
I fixed it using plain old jsp. On Save, I just did this
vuedata.dateOfBirthMilliSecs = $("#dateOfBirth").val() ;
I'll figure out conversion of date format to milliseconds in my java controller.
Related
The structure of my code is like this:
So in the Product component, I am making an API call:
<template>
<button class="btn button col-2" #click="addToCart()">
Add to cart
</button>
</template>
<script>
methods:{
addToCart: function () {
let amount = this.itemsCount !== "" ? this.itemsCount : 1;
if(this.variationId != null) {
this.warningMessage = false;
cartHelper.addToCart(this.product.id, this.variationId, amount, (response) => {
this.cartItems = response.data.attributes.items;
});
} else {
this.warningMessage = true;
}
console.log(this.cartItems)
},
}
</script>
And what I am trying to do is the response (this.cartItems) should be shown in Cart component. And my Navbar component:
<template>
<nav class="navbar navbar-expand-lg shadow">
<div class="container navbar-container">
<div class="navbar navbar-profile">
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" id="dropdownCart" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fa fa-fw fa-cart-arrow-down"></i>
<span></span>
</button>
<div #click="$event.stopPropagation()">
<CartBox :cartItems="cartItems"/>
</div>
</div>
</div>
</div>
</nav>
</template>
<script>
export default {
props: {
cartItems:Object
},
components: {CartBox},
}
And CartBox:
<template>
<Cart/>
</template>
<script>
import Cart from '../components/Cart'
export default {
components: {
Cart
}
}
</script>
And my Cart component:
<template>
<div
class="dropdown-menu cart"
aria-labelledby="triggerId"
>
<div class="inner-cart">
<div>
<div class="cart-items">
<div>
<a class="remove">Remove</a>
</div>
</div>
</div>
<hr/>
<div class="cart-items-total">
<span>Total:</span>
Clear Cart
</div>
<hr/>
<router-link :to="{name: 'order'}" class="btn button-secondary">Go To Cart</router-link>
</div>
</div>
</template>
<script>
export default {
computed: {
},
methods: {
}
};
</script>
I am really confused how to pass the props to sibling component and then the child component but if you could pass it to Cart component, that would really help me.
There are two approaches for your request:
1. Using props, provide and inject
This could be accomplished with Provide / inject, after passing your response to a parent. Basically, you will emit your response from your Product component to a parent, maybe like your App.vue as the prop myData, then you provide it for every child, no matter where it is nested, like this:
provide: {
providedData: this.myData
}
In any child you can now use:
inject: ['providedData']
Please note, that this data will only be available if your Product component received it. The second approach is recommended.
2. Using a store
Using a store like vuex is a bit more complex than approach 1, but it will save a lot of time in the future. You would recieve your response in your Product component, dispatch it to the store and could call the state of information from this store anywhere in your app. See further information in this documentation: Vuex | Getting Started
I have multiple text inputs generated in v-for directive which i have attached to one v-model variable as show below. I have a button by the respective inputs which prints the value of the current working input. Ultimately I want to extract value of the selected input without affecting the other inputs.
But apparent any change make in one input affect all the input. I super confused as to how I will achieve this. Any help will be much appreciated.
My attempted code is shown below.
<template>
<div id="app">
<div v-for="i in 5" :key="i">
<input v-model="text" type="text" :key="i" />
<button #click="printText">print</button> <span>{{ text }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
text: "",
};
},
methods: {
printText() {
console.log(this.text);
},
},
};
</script>
Take an array instead of simple variable when you use v-model in v-for
And on click pass the index with function call
Try to use
<template>
<div id="app">
<div v-for="i in 5" :key="i">
<input v-model="text[i]" type="text"/>
<button #click="printText(i)">print</button> <span>{{ text[i] }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
text: [],
};
},
methods: {
printText(index) {
console.log(this.text[index]);
},
},
};
</script>
i using vee-validate version 3.0.11 for validate my form like below
<validation-observer v-slot="{ invalid }" slim>
<validation-provider rules="required" v-slot="{ errors, dirty, invalid}" slim>
<div class="form-group">
<label class="sr-only" for="txtUsername"></label>
<input
autocomplete="off"
id="txtUsername"
name="username"
type="text"
class="form-control txtUsername"
placeholder="Email or Username"
v-model="username"
v-bind:class="{ 'is-invalid': invalid && dirty,'is-valid': !invalid }" />
</div>
</validation-provider>
<validation-provider rules="required" v-slot="{ errors, dirty, invalid}" slim>
<div class="form-group">
<label class="sr-only" for="txtPassword"></label>
<input
id="txtPassword"
name="password"
type="password"
class="form-control"
placeholder="Password"
v-model="password"
v-bind:class="{ 'is-invalid': invalid && dirty,'is-valid': !invalid }" />
</div>
</validation-provider>
<div >
<button
type="button"
name="login"
class="btn btn-primary"
v-on:click="doLogin()"
:disabled="invalid">
Login
</button>
</div>
</validation-observer>
and i wrote some test with chai and mocha
in my test i need to find the button
but when i using find method for find button all html tag between validation-observer tag is not loaded in my wrapper.
my test code is:
// i change it to shallowMount to mount but problem is exist,
// mount does not render any thing between validation-observer tag
const wrapper = mount(LoginView, { sync: false });
describe('Login.vue', () => {
it('some text, () => {
console.log(wrapper.html());
// my log include all of tag except tags between the validation-observer tag
});
});
can some one tell me how i can find my button by using warraper.find(), please?
You are trying to shallow mount a component that needs to be mounted in order to render its children. If you want to ignore ValidationProvider all together you can provide a fake one as shown below.
ContactForm.vue
<template>
<div>
<ValidationProvider rules="required" name="input" v-slot="{ errors }">
<p :style="{color: 'red'}">To be, or not to be</p>
<input type="text" v-model="value">
<span id="error">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</template>
<script>
import { ValidationProvider } from "vee-validate";
export default {
name: "ContactForm",
components: {
ValidationProvider
},
data: () => ({
value: ""
})
};
</script>
ContactForm.test.js
import { shallowMount, createLocalVue } from "#vue/test-utils";
import ContactForm from "./ContactForm";
import FakeValidationProvider from "./FakeValidationProvider";
test("Test shallow mount renders what's inside validation provider", async () => {
const localVue = createLocalVue();
var wrapper = shallowMount(ContactForm, {
stubs: {
ValidationProvider: FakeValidationProvider
},
localVue
});
expect(wrapper.text()).toContain("To be, or not to be");
});
FakeValidationProvider.vue
<template>
<div v-bind="{ ...$props, ...$attrs }">
<slot :errors="errors"></slot>
</div>
</template>
<script>
export default {
name: "FakeValidationProvider",
data() {
return {
errors: []
};
}
};
</script>
Feel free to extend the slot with any other parameters you need besides errors. If you want to make those parameters dynamic as well, check out this article on rendering slots
My objective is to get text from an input that's in a template. Not sure how to go about retrieving this. I'm using Vue; Note must be available in Vue.js, no external sources
The Template:
<template id="addmodal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
Enter Course Information:
</slot>
</div>
<div class="modal-body">
<slot name="body">
Course Name
<input type="text" ref="coursename" placeholder="Numbers Don't Lie 101">
Course Grade
<input type="text" ref ="coursemark" placeholder="100">
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<button class="modal-default-button" #click="confirmCourse">
Submit New Course
</button>
<button class="modal-cancel-button" #click="cancelCourse">
Cancel
</button>
</slot>
</div>
</div>
</div>
</div>
</template>
I need to access coursename and coursemark. This can be done fairly easily when not inside a template. As it is right now the code executes stating .value is undefined.
var app = new Vue({
el: "#app",
data: {
courses: [],
confirmModal: false,
confirmAdd: false,
selectedCourse: null
},
methods: {
addCourse2: function addCourse2() {
this.confirmAdd = false;
var course = this.$refs.coursename.value;
var mark = this.$refs.coursemark.value;
if (course) {
this.courses.push(new Course(course, mark));
this.$refs.newcourse.value = "";
this.$refs.newmark.value = "";
}
}
}
});
EDIT:
Forgot to add the component section
Vue.component("add-modal", {
template: "#addmodal",
props: ["open", "course", "mark"],
methods: {
confirmCourse: function confirmCourse() {
alert(this.$refs.coursename.value);
this.$emit("confirm");// GET
},
cancelCourse: function cancelCourse() {
this.$emit("cancel");
}
}
});
Forgive me in advance, I feel this is something rather easy I'm missing as a beginner
use v-model. or if it is in other component. you can use $emit
Not too sure what is wrong here, it seems fine to me! I'm simply trying to update the data property display to true when I click the input within my component.
I have passed the data to the slot scope, so can't see that being the issue. It just simply won't update, using a function to toggle it works, however not what I really want to do, seems pointless.
<time-select>
<div slot-scope="{ time }" class="is-inline-block">
<label for="businessHoursTimeFrom"><i class="fas fa-clock"></i> From</label>
<input type="text" name="businessHoursTimeFrom[]" v-model="time" v-on:click="display = true">
</div>
</time-select>
The code behind:
<template>
<div>
<p>{{ display }}</p>
<slot :time="time" :display="display"></slot>
<div class="picker" v-if="display">
<p>Test</p>
</div>
</div>
</template>
<script>
export default {
props: [],
data: function () {
return {
time: '',
display: false
}
},
mounted() {
},
methods: {
}
}
</script>