I get all data from firebase and store it on array and from that array i take all posted_at data (time when was something posted). My goal is to retrieve all that data in some sort of time format and problem is that it won't retrieve multiple values. I am using Vuejs.
<template>
<div v-for="data in array">
{{ time }}
</div>
</template>
<script>
import moment from 'moment'
export default{
data(){
return{
array:[]//example:1577200868199, 1577200868189,...
}
},
computed:{
time(){
moment(this.array.posted_at).format('MMMM Do YYYY, h:mm:ss a')
}
}
}
</script>
P.S. I have tried using a for and a while loop but it's not working
This is a nice case to use Vue filter
<template>
<div v-for="data in array">
{{ data | formatTime }}
</div>
</template>
<script>
import moment from 'moment'
export default{
data(){
return{
array: []//example:1577200868199, 1577200868189,...
}
},
filters: {
formatTime: function (value) {
return moment(value).format('MMMM Do YYYY, h:mm:ss a')
}
}
}
</script>
With moment you can only parse one item at a time, so you can change your code to loop over your array and parse each item individually. It would look something like this.
this.array.forReach(posted_at => {
moment(posted_at).format('MMMM Do YYYY, h:mm:ss a')
})
Related
I have a search bar on the root component (App.vue). I want to enter a query and on #keyup.enter, it should redirect to the Search component view with the v-text-field input value. Redirection is used by using $router.replace because users might search for a different keyword from within the same route.
The code below work but only ONCE. If I enter a new search term, the URL changed but the results stay the same.
App.vue
<template>
<div>
<header>
<v-text-field #keyup.enter="goToSearchPage($event)"></v-text-field>
</header>
<v-main>
<router-view></router-view>
</v-main>
</div>
</template>
<script>
export default {
methods: {
goToSearchPage($event) {
this.$router.replace({
name: "Search",
query: { q: $event.target.value }
});
}
}
};
</script>
views/Search.vue
<template>
<div>
<ais-instant-search
index-name="dev_brunjar_products"
:search-client="searchClient"
:search-function="searchFunction"
>
<ais-hits>
<ul slot-scope="{ items }">
<li v-for="item in items" :key="item.objectID">
{{ item.name }}
</li>
</ul>
</ais-hits>
</ais-instant-search>
</div>
</template>
<script>
import algoliasearch from "algoliasearch/lite";
export default {
data() {
return {
searchClient: algoliasearch(
process.env.VUE_APP_ALGOLIA_APP_ID,
process.env.VUE_APP_ALGOLIA_SEARCH_KEY
)
};
},
methods: {
// According to Algolia's doc, this should be inside data instead of methods
// https://www.algolia.com/doc/api-reference/widgets/instantsearch/vue/#widget-param-search-function
// But doing so, I wouldn't be able to get this.$route.query.q
searchFunction(helper) {
var query = this.$route.query.q;
if (query) {
helper.setQuery(query).search();
}
}
}
};
</script>
What I've tried
Did a hack-ish way (Test 1) to solve it but didn't work (which I'm glad, because it doesn't feel right). Below was the non-working code addition to the Search component. Created computed & watch property of query which get its data from this.$route.query.q and algoliaHelper data assigned with AlgoliaSearchHelper when the searchFunction first load.
When I typed a new search term, the watcher works and the query indeed changed. Despite that, calling the helper and setting its query with the new term within the watcher did not change the results from Algolia.
Then I used Routing URLs (Test 2) to the ais-instant-search and it still didn't solve the issue. Maybe I'm implementing it wrong? I really tried to understand Algolia's doc and it's just too hard to digest.
views/Search.vue - Test 1 (Failed)
<template>
<div>
<ais-instant-search
index-name="dev_brunjar_products"
:search-client="searchClient"
:search-function="searchFunction"
>
<ais-hits>
<ul slot-scope="{ items }">
<li v-for="item in items" :key="item.objectID">
{{ item.name }}
</li>
</ul>
</ais-hits>
</ais-instant-search>
</div>
</template>
<script>
import algoliasearch from "algoliasearch/lite";
export default {
data() {
return {
searchClient: algoliasearch(
process.env.VUE_APP_ALGOLIA_APP_ID,
process.env.VUE_APP_ALGOLIA_SEARCH_KEY
),
algoliaHelper: null
};
},
computed: {
query() {
return this.$route.query.q;
}
},
watch: {
query(newQuery) {
this.algoliaHelper.setQuery(newQuery).search();
}
},
methods: {
searchFunction(helper) {
if (!this.algoliaHelper) {
this.algoliaHelper = helper;
}
if (this.query) {
helper.setQuery(this.query).search();
}
}
}
};
</script>
views/Search.vue - Test 2 (Failed)
<template>
<div>
<ais-instant-search
index-name="dev_brunjar_products"
:search-client="searchClient"
:search-function="searchFunction"
:routing="routing"
>
<ais-hits>
<ul slot-scope="{ items }">
<li v-for="item in items" :key="item.objectID">
{{ item.name }}
</li>
</ul>
</ais-hits>
</ais-instant-search>
</div>
</template>
<script>
import { history as historyRouter } from "instantsearch.js/es/lib/routers";
import { singleIndex as singleIndexMapping } from "instantsearch.js/es/lib/stateMappings";
import algoliasearch from "algoliasearch/lite";
export default {
data() {
return {
searchClient: algoliasearch(
process.env.VUE_APP_ALGOLIA_APP_ID,
process.env.VUE_APP_ALGOLIA_SEARCH_KEY
),
routing: {
router: historyRouter(),
stateMapping: singleIndexMapping("instant_search")
}
};
},
methods: {
searchFunction(helper) {
if (this.query) {
helper.setQuery(this.query).search();
}
}
}
};
</script>
I would appreciate it if you guys know how to solve this issue.
https://codesandbox.io/s/github/algolia/doc-code-samples/tree/master/Vue%20InstantSearch/routing-vue-router?file=/src/views/Home.vue
This is an example using vue router. I guess this might be what you're looking for.
Please let us know if it works for you.
Hope you where able to solve this since it's been a long time since you asked. But, in order to make it work you have to put searchFunction(helper) inside data() as shown in the docs: https://www.algolia.com/doc/api-reference/widgets/instantsearch/vue/#widget-param-search-function
I'm pretty new to VueJS and have an understanding problem i couldn't find any help for.
Its pretty simple: I'm getting a JSON through an API with axios. This item contains a description that I want to output on the page.
My code looks something like this:
<template>
<div v-for="item in listitems" :key="item.id">
{{ item.description }}
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import axios from 'axios'
export default defineComponent({
name: 'AllCoupons',
components: {
},
data: function() {
return {
listitems :[]
}
},
mounted: function() {
axios.get('https://api.com/endpoint',
{
headers: {
'Accept': 'application/json'
}
}).then((response) => {
console.log(response);
this.listitems = response.data.data
}).catch(error => {
console.log("ERRR:: ", error.response.data)
});
}
});
</script>
It works fine so far. The problem is that the item.description has too many characters, which I'd like to limit with something like substr. What is the right / best way to do something like this in vue?
I thought about adding a custom function in methods which will be run after the api fetched the data to iterate trough the data and make the modifications then, before passing it back to this.listitems. - But is there a way to do something like this in the template: ?
{{ item.description.substring(1, 4); }}
I knew something like this was possible with Vue 2 and filters if I'm right... But how can I do something like this in Vue 3?
Thanks a lot!!
As suggested in migration guide, you could use a computed property like :
data: function() {
return {
listitems :[]
}
},
computed:{
customItems(){
return this.listitems.map(item=>{
return {...item, description:item.description.substring(1, 4)}
}
}
}
then render that computed property :
<div v-for="item in customItems" :key="item.id">
{{ item.description }}
</div>
Probably a basic question, but I'm just beginning to learn Vue/Javascript in general.
I have a basic DatePicker component DatePicker.vue:
<template>
<div>
<md-datepicker v-model="selectedDate">
<label>Select date</label>
</md-datepicker>
</div>
</template>
<script>
import Vue from "vue";
export default Vue.extend( {
name: "LabeledDatepicker",
data: () => ({
selectedDate: null,
}),
});
</script>
This component is used in a view like so:
<template>
<div class="date-picker">
<DatePicker />
</div>
</template>
In my script I have two properties called fromDate and toDate which I want to get from two datepickers in my component.
<script lang="ts">
import Vue from "vue";
import DatePicker from "./DatePicker.vue";
export default Vue.extend({
components: {
DatePicker,
},
data() {
return {
fromDate: null,
toDate: null,
};
How do I bind the values selected in the datepickers to fromDate and toDate so I can use them in my API requests? I have tried to use v-model="fromDate", but fromDate was still null even after I selected a date.
Your datepicker component needs to accept props if you want to both populate the value with existing values and update it from within the component. Alternatively, use "emit" from your datepicker component and then attach a method to handle change custom event in Vue.js
I'm new to Date-FNS and I need to get this example to work in VueJS:
import { format, formatDistance, formatRelative, subDays } from 'date-fns'
format(new Date(), '[Today is a] dddd')
//=> "Today is a Wednesday"
formatDistance(subDays(new Date(), 3), new Date())
//=> "3 days ago"
formatRelative(subDays(new Date(), 3), new Date())
//=> "last Friday at 7:26 p.m."
How to get it to work?
Just like moment js, all you need is to use the date library is to import and include it in your data:
import { format, formatDistance, formatRelative, subDays } from 'date-fns'
export default {
data () {
return {
format,
}
}
}
And now in your template, you can use format as:
<template>
<p> Today's date is: {{ format(new Date(), 'dddd') }} </p>
</template>
With Locale:
I haven't tried the locale but it seems very straight forward. According to the manual I think this should work.
import { format, formatDistance, formatRelative, subDays } from 'date-fns'
import es from 'date-fns/locale/es'
window.locale = 'es'
export default {
data () {
return {
format,
}
},
methods: {
getFormat () {
return this.format(new Date(), 'dddd', {locale: window.locale})
}
}
}
And now in your template, you can use format as:
<template>
<p> Today's date is: {{ getFormat() }} </p>
</template>
I think if you spend a couple of minutes with it, you can get a better working solution for you.
Update with lazy loading approach
This option is good if you need to support many locales and want to pay attention to bundle sizes.
let dateFnsLocale
if (lang === 'en') { dateFnsLocale = await import('date-fns/locale/en-US') }
if (lang === 'hu') { dateFnsLocale = await import('date-fns/locale/hu') }
if (lang === 'fr') { dateFnsLocale = await import('date-fns/locale/fr') }
The reason why I'm not dynamically concatenating the lang to the import string is because I've found that in that case Webpack will not be able to decide which locales you'll import, and it takes all.
Personally I've started to store the dateFnsLocale in Vuex, so once your import is done you can commit it to state if you want, making it accessible throughout your application similarly as the global namespace of window did.
Original answer
If you need to support multiple locales I think it's best to do this in your main.js.
import { default as en } from 'date-fns/locale/en'
import { default as hu } from 'date-fns/locale/hu'
import { default as fr } from 'date-fns/locale/fr'
window.dateFnsLocales = {
hu,
fr,
en
}
Then anywhere in your script tags you can:
format(new Date(), 'dddd', {locale: window.dateFnsLocales[CURRENTLY SELECTED LOCALE]})
In the version v1.30.1 of date-fns you have to import/require from date-fns/something.
In order to make it work with Vuejs:
import format from "date-fns/format"
import distanceInWords from "date-fns/distance_in_words"
import subDays from "date-fns/sub_days"
export default {
name: "MyComponent",
computed: {
inWords () { return distanceInWords(subDays(new Date(), 3), new Date()) },
today () { return format(new Date(), '[Today is a] dddd') },
},
}
And the template tag:
<template>
<div>
<p>{{ inWords }}</p>
<p>{{ today }}</p>
</div>
</template>
Just got it to work:
In your template:
{{ formatDate() }}
Import:
import format from 'date-fns/format'
export default {
...
In your Method:
methods: {
formatDate: function () {
return format(new Date(), '[Today is a] dddd')
},
I have this component:
<template>
<div class="animated fadeIn">
<div class="col-sm-6 col-lg-6">
<datepicker class="form-control" :value="config.state.fromDate" :disabled="config.disabledFrom"></datepicker>
</div>
<div class="col-sm-6 col-lg-6">
<datepicker :value="config.state.toDate" :disabled="config.disabledTo"></datepicker>
</div>
</div>
</template>
<script>
import Datepicker from 'vuejs-datepicker'
var d = new Date()
var year = d.getFullYear()
var month = d.getMonth()
var day = d.getDate()
var fromD = new Date(year - 1, month, day)
var toDD = new Date(year, month, day)
console.log(fromD.toString())
console.log(toDD)
export default {
data() {
return {
config: {
disabledFrom: {
to: fromD
},
disabledTo: {
from: toDD
},
state: {
fromDate: (d.getDate() - 1).toString(),
toDate: new Date(year, month, day).toString()
}
}
}
},
components: {
Datepicker
}
}
</script>
I import this component like so:
import picker from '../components/DateFilter'
In this vue I have a button that when clicked i want it to get a property from the component that I am importing:
<template>
<div class="animated fadeIn">
<picker></picker>
</div>
<div>
<button #click="onChange2" class="btn btn-primary">search</button>
</div>
</template>
the method has an alert to show me the value:
onChange2: function() {
alert(picker.datepicker.value)
}
error message:
Cannot read property 'value' of undefined
other attempts:
alert(picker.data.config.state.value)
alert(picker.config.state.value)
I am new to vue and I havent been able to figure out where I am doing this wrong.
It is techincally possible to access child properties by using this.$children (or this.$parent) but please dont! It will introduce coupling between your components which is bad, very bad.
Instead you should use props to pass data down to your children, and emit events up to your parents.
If this is the vue-datepicker you are using, here's one example to do what you want:
// childcomponent.vue
<template>
<div class="child-component">
<datepicker v-on:selected="doSomethingInParentComponentFunction"></datepicker>
</div>
</template>
<script>
import Datepicker from 'vuejs-datepicker'
export default {
components: {
Datepicker
},
methods: {
doSomethingInParentComponentFunction (selectedDate) {
this.$emit("selected", selectedDate)
}
}
}
</script>
And in parent:
// parentcomponent.vue
<template>
<div class="parent-component">
<child-component v-on:selected="dateSelectedInChild"></child-component>
</div>
</template>
<script>
import ChildComponent from 'childcomponent'
export default {
components: {
ChildComponent
},
methods: {
dateSelectedInChild (selectedDate) {
console.log(selectedDate)
}
}
}
</script>
You can read more about this on the links above, or on this article which summarize this and more.
picker is a component class, not an instance of a component. It doesn't have any properties you can access. Similarly, Datepicker (not datepicker, which is just the HTML tag form) is a component, not an instance.
You're thinking about Vue data backwards. You provide initial values to your datepickers, but you don't have them storing new values anywhere. You expect to be able to "look into" children to get values, but instead, you should be sending those values out of the children via events (read this).