I'm trying to bind datetime with the flip-countdown component so that it reads the date and time to start displaying and counting down the time.
My issue is that it can't read the time, or the datetime is not bound with the flip-countdown component.
The template:
<template>
<div class="container-fluid">
<div class="row">
<div class="col-lg-4" dir="ltr">
<flip-countdown v-bind:deadline="this.time|created_at" :showDays="false"></flip-countdown>
</div>
</div>
</div>
</template>
The script:
import FlipCountdown from 'vue2-flip-countdown'
export default {
components: { FlipCountdown },
name: "TimeEntry",
data() {
return {
time: '',
}
},
methods: {
getTime(){
axios.get('/api/last_time')
.then(({data}) => {
console.log(data.time);
// this.times = data.times.data;
this.time = data.time;
})
}
},
created() {
this.getTime();
}
API Route:
Route::get('/last_time', function (){
$tim = \App\TimeEntry::latest()->where('time_end', null)->first()->created_at;
$time = \Carbon\Carbon::parse($tim)->addHour(7);
return response()->json(['time'=>$time]);
});
Filter:
Vue.filter('created_at', function(time_end){
return moment(time_end).format('YYYY-MM-DD HH:mm:ss')
});
I tried to display the value of: this.time|created_at in <p>{{ this.time|created_at }} </p>, and the output was: 2020-07-23 18:58:07.
Vue filters are intended to be used in string interpolation, not bindings.
One solution is to use a computed prop that returns the time formatted:
<template>
<flip-countdown :deadline="formattedTime" :showDays="false"></flip-countdown>
</template>
<script>
import moment from 'moment'
export default {
//...
computed: {
formattedTime() {
return moment(this.time).format('YYYY-MM-DD HH:mm:ss')
}
}
}
</script>
Related
Need help , i can get all data from response api but having some problem when try to get data (looping data ) from key "get_item_cards" . Here's my response and code in vue js
Response api
<script setup>
<script>
import axios from 'axios'
export default {
name: 'ListNotes',
data() {
return {
cardNotes: [],
}
},
mounted() {
// console.log('Page mounted');
this.getListNotes();
},
methods: {
getListNotes() {
axios.get('http://localhost:8000/api/card').then(res => {
this.cardNotes = res.data.cardNotes
console.log(this.cardNotes);
})
}
}
}
</script>
how the best way to get all data & each data from relationship in vue js 3
Since the this.cardNote returns an array with three elements, you can use loop using v-for and access to the get_item_cards array like below,
<template>
<div>
<div v-for=(note, index) in cardNote>
<p>{{node.cardname}}</p>
<div v-for=(item, key) in note.get_item_cards>
<p>{{item.content}}</p>
</div>
</div>
</div>
</template>
<script setup>
<script>
import axios from 'axios'
export default {
name: 'ListNotes',
data() {
return {
cardNotes: [],
}
},
mounted() {
// console.log('Page mounted');
this.getListNotes();
},
methods: {
getListNotes() {
axios.get('http://localhost:8000/api/card').then(res => {
this.cardNotes = res.data.cardNotes
console.log(this.cardNotes);
})
}
}
}
</script>
I am very new to Laravel and Vuex, I have a simple array of post on my page.
test 1
test 2
test 3
I am trying to link the text on the AppPost.vue component and show the post that has been clicked on a new component (AppShowpost.vue) on the same page. I believe I have to get the post by id and change the state? any help would be good. Thank you.
when you click test 1 it will show "test 1" on a new component (AppShowpost.vue)
In side my store timeline.js, I belive I need to get the post by id and change the state ?
import axios from 'axios'
export default {
namespaced: true,
state: {
posts: []
},
getters: {
posts (state) {
return state.posts
}
},
mutations: {
PUSH_POSTS (state, data) {
state.posts.push(...data)
}
},
actions: {
async getPosts ({ commit }) {
let response = await axios.get('timeline')
commit('PUSH_POSTS', response.data.data)
}
}
}
My AppTimeline.vue component
<template>
<div>
<app-post
v-for="post in posts"
:key="post.id"
:post="post"
/>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
export default {
computed: {
...mapGetters({
posts: 'timeline/posts'
})
},
methods: {
...mapActions({
getPosts: 'timeline/getPosts'
})
},
mounted () {
this.getPosts()
}
}
</script>
My AppPost.vue component. I need to link the post.body to display the post in my AppShowpost.vue component.
<template>
<div class="w-full inline-block p-4">
<div class="flex w-full">
<p>
{{ post.body }}
</p>
</div>
</div>
</template>
<script>
export default {
props: {
post: {
required: true,
type: Object
}
}
}
</script>
My AppSowpost.vue component that needs to display the post that is clicked.
<template>
<div>
// Displaypost ?
</div>
</template>
<script>
export default {
// Get post from id ?
}
</script>
Okay you can create a new state in your vuex "current_state", asyou said, you can dispatch a mutation by passing the id to the vuex.
state: {
posts: [],
current_state_id : null
},
In your mutations
set_state_id (state, data) {
state.current_state_id = data;
}
On your app post.vue, you can set a computed property that watches the current state
computed: {
currentState() {
return this.$store.getters["timeline/current_state_id"];
}}
And create a watcher for the computed property to display the current id/post
watch: {
currentState: function(val) {
console.log(val);
},
Maybe this will help you. First I will recommend to use router-link. Read about router link here if your interested. It is very helpful and easy to use. But you will have to define the url and pass parameter on our vue-route(see bellow).
1.You can wrap your post.body in router-link as follow.
//With this approach, you don't need any function in methods
<router-link :to="'/posts/show/' + post.id">
{{ post.body }}
</router-link>
2. In your AppSowpost.vue component, you can find the post in vuex state based on url params as follow.
<template>
<div> {{ thisPost.body }} </div>
</template>
// ****************
computed: {
...mapState({ posts: state=>state.posts }),
// Let's get our single post with the help of url parameter passed on our url
thisPost() { return this.posts.find(p => p.id == this.$route.params.id) || {}; }
},
mounted() { this.$store.dispatch("getPosts");}
3. Let's define our vue route.
path: "posts/show/:id",
name: "showpost",
params: true, // Make sure the params is set to true
component: () => import("#/Components/AppShowPost.vue"),
Your Mutations should look as simple as this.
mutations: {
PUSH_POSTS (state, data) {
state.posts = data;
}
},
Please let me know how it goes.
I have a Vue component that makes a post request, and then outputs the returned html.
Sometimes, the html that is returned by the post contains Vue directives.
Is there a way to have Vue parse the returned html before it is output?
(In the longer term, I will rewrite this as a pure Vue solution, with the post request returning data rather than html. I'm after a short term solution if its possible).
EDIT:
Here's my stab based on thanksd's suggestion but I'm not sure how to bind the new Vue instance to an html element.
<template>
<div>
<input type="text" class="form-control" v-model="value" #change="getResults" ></input>
<div>
<template v-bind="results"></template>
</div>
</div>
</template>
<script>
import{eventHub} from '../utils/event.js'
export default {
data : function(){
return {
value : '',
results : {}
}
},
methods:{
getResults(){
if(this.value.length < 3){return;}
this.$http.post('/ajax/search',{search:this.value}).then((response)=>{
this.results = Vue({template:response.body});
});
},
},
}
After the post request returns you could create a new Vue instance, passing the html as the template and binding it to an element in your current Vue instance's template:
<template>
<div>
<input type="text" class="form-control" v-model="value" #change="getResults" ></input>
<div>
<div id="results"></div>
</div>
</div>
</template>
<script>
export default {
data() {
return { value: '' }
},
methods: {
getResults() {
if (this.value.length < 3) {
return;
}
this.$http.post('/ajax/search', { search: this.value }).then((response) => {
new Vue({ el: '#results', template: response.body });
});
}
}
}
</script>
Or as #Bert pointed out, you could add a <component> tag to your template and pass its definition via the is prop:
<template>
<div>
<input type="text" class="form-control" v-model="value" #change="getResults" ></input>
<component :is="results"/>
</div>
</template>
<script>
export default {
data() {
return {
value: '',
results: null
}
},
methods: {
getResults() {
if (this.value.length < 3) {
return;
}
this.$http.post('/ajax/search', { search: this.value }).then((response) => {
this.results = { template: response.body };
});
}
}
}
</script>
I am validating a input field ( required , min length 3 ) with VeeValidate plugin.. it's working fine
but how I can avoid the onInput action to be called ( to avoid commit in store when the input becomes invalid ( as soon as input aria-invalid switch to false )
shortly said : Is there anyway to switch calling/not Calling onInput: 'changeTitle' when the input field aria-invalid is false/true ?
thanks for feedback
ChangeTitleComponent.vue
<template>
<div>
<em>Change the title of your shopping list here</em>
<input name="title" data-vv-delay="1000" v-validate="'required|min:3'" :class="{'input': true, 'is-danger': errors.has('required') }" :value="title" #input="onInput({ title: $event.target.value, id: id })"/>
<p v-show="errors.has('title')">{{ errors.first('title') }}</p>
</div>
</template>
<style scoped>
</style>
<script>
import { mapActions } from 'vuex'
import Vue from 'vue'
import VeeValidate from 'vee-validate'
Vue.use(VeeValidate)
export default {
props: ['title', 'id'],
methods: mapActions({ // dispatching actions in components
onInput: 'changeTitle'
})
}
</script>
vuex/actions.js
import * as types from './mutation_types'
import api from '../api'
import getters from './getters'
export default {
...
changeTitle: (store, data) => {
store.commit(types.CHANGE_TITLE, data)
store.dispatch('updateList', data.id)
},
updateList: (store, id) => {
let shoppingList = getters.getListById(store.state, id)
return api.updateShoppingList(shoppingList)
.then(response => {
return response
})
.catch(error => {
throw error
})
},
...
}
UPDATE
I tried to capture the input value with #input="testValidation) and check for a valid input value (required)
if valid ( aria-invalid: false) then I emit the input value, but the props are not updated in the parent component and the vuex action 'changeTitle' is not triggered
<template>
<div>
<em>Change the title of your shopping list here</em>
<input name="title" ref="inputTitle" data-vv-delay="1000" v-validate="'required'" :class="{'input': true, 'is-danger': errors.has('required') }" :value="title" #input="testValidation({ title: $event.target.value, id: id })"/>
<p v-show="errors.has('title')">{{ errors.first('title') }}</p>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import Vue from 'vue'
import VeeValidate from 'vee-validate'
Vue.use(VeeValidate)
export default {
props: ['title', 'id'],
methods: {
testValidation: function (value) {
const ariaInvalid = this.$refs.inputTitle.getAttribute('aria-invalid')
if (ariaInvalid === 'false') {
this.$nextTick(() => {
this.$emit('input', value) // should change props in parent components
})
} else {
console.log('INVALID !') // do not change props
}
},
...mapActions({
onInput: 'changeTitle' // update store
})
}
}
</script>
like you access the errors collection in the VUE template, you can also access the same errors collection in your testValidation method
so replace
const ariaInvalid = this.$refs.inputTitle.getAttribute('aria-invalid')
with
const ariaInvalid = this.$validator.errors.has('title')
grtz
I am new to VueJs with Laravel. I have a component called Event in which a 'read more...' link shoud trigger a function that fetch the event infos from the data base and store the in a variable withing this same component.
Here is the code for my component:
<template>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h5>
Title: {{ event.event_name }}
<span class="pull-right">
#click=getEventInfo(event.id)>Read more ...</a></span>
</h5>
<h5>publised by: {{ event.user.name }}
<span class="pull-right" v-text="timeFromNow(event.created_at)"></span>
</h5>
</div>
<div class="panel-body">
<p>{{ event.event_detail }}</p>
</div>
<div class="panel-footer">
<p>
<span>Event for: {{ event.event_to_whom }}</span>
<span>When: {{ dayOfDate(event.event_when_date) }} {{ event.event_when_date }} at {{event.event_when_time}}</span>
</p>
</div>
</div>
</div>
</template>
<script>
import moment from 'moment';
export default {
name: 'app-event',
props:['event'],
data() {
return {
eventInfo: {}
}
},
methods: {
timeFromNow(tmp) {
return moment(tmp).fromNow();
},
dayOfDate(d) {
let dt = moment(d, "YYYY-MM-DD");
return dt.format('dddd');
},
//event.id
getEventInfo(id){
let url = 'events/' + id;
axios.get(url)
.then((response) => {
console.log(response.data); //returns data
this.eventInfo = response.data;
console.log(this.eventInfo);//returns data
});
console.log(this.eventInfo); //returns nothing
}
}
}
</script>
The problem is when I click the 'read more...' link axios returns a response that I can check using console.log(response.data). Hovever when I console.log(this.eventInfo) outside the axios closure, it returns and ampty object.
Am I doing something wrong? Sorry if the question is too basic.
Thanks
L.B
You are printing logging the property before it is assigned a value.
The code below should resolve any errors
import moment from 'moment';
export default {
name: 'app-event',
props:['event'],
data() {
return {
eventInfo: {}
}
},
methods: {
timeFromNow(tmp) {
return moment(tmp).fromNow();
},
dayOfDate(d) {
let dt = moment(d, "YYYY-MM-DD");
return dt.format('dddd');
},
//event.id
getEventInfo(id){
let url = 'events/' + id;
axios.get(url)
.then((response) => this.handleResponse(response.data));
},
handleResponse(eventInfo) {
console.log(eventInfo);
// do something with the eventInfo...
}
}
Your axios call is asynchrone so your outside console.log will be process before the return of the response.
Just keep your code in the .then((response) => { // here i proceed the read more }