How can I modify props values once the page has been refreshed in Vue? - vue.js

My test code is the following, it's just an example to understand my question.
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const props = defineProps({
account: Object,
})
const { account } = toRefs(props);
const accountDate = ref("")
const formatDate = (date) => {
var d = new Date(date)
var month = '' + (d.getMonth() + 1)
var day = '' + d.getDate()
var year = d.getFullYear()
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('-');
}
onMounted(() => {
accountDate.value = formatDate(account.value.date)
console.log(account.value.date)
})
</script>
<template>
<input type="text" v-model="accountDate"></input>
</template>
So the "formatDate" function just transforms Date format to YYYY-MM-DD, it's not important in my question. So I v-model accountDate with the new Date format but the console.log shown just print "undefined". So props are not defined yet in onMounted lifecycle.
How can I do it?

Related

Why the slice method doesn't work on array prop?

I have the following code which defines a Pinia storage:
import { ref, computed, shallowRef } from 'vue'
import { defineStore } from 'pinia'
export const usePokemonStore = defineStore('pokemons', () => {
// define the pokemons list state
const pokemonsList = ref([]);
const pokemonsLoaded = ref([]);
const pokemonsLoadedNames = ref([]);
// computed
const pokemonsListLength = computed(() => pokemonsList.value.length)
const pokemonsLoadedLength = computed(() => pokemonsLoaded.value.length)
// actions
async function getList() {
const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0');
const data = await res.json();
pokemonsList.value = data["results"];
}
async function loadPokemon(name) {
const URI = `https://pokeapi.co/api/v2/pokemon/${name}`
const res = await fetch(URI);
const data = await res.json();
pokemonsLoadedNames.value.push(data["name"])
pokemonsLoaded.value.push(data)
}
async function loadPokemons(offset, limit){
// basic check for limits
limit = limit > pokemonsListLength ? pokemonsListLength : limit;
limit = limit < 0 ? 10 : limit
// basic check for offset
offset = offset < 0 ? 0 : offset;
offset = offset > pokemonsListLength ? 0 : offset
for (let i = offset; i < offset+limit; i++){
// if the pokemon is already loaded skips the request for it
if (pokemonsLoadedNames.value.includes(pokemonsList.value[i].name)) {
continue;
}
// requests the pokemon given a name
loadPokemon(pokemonsList.value[i].name)
}
}
return {
pokemonsList,
pokemonsLoaded,
pokemonsListLength,
pokemonsLoadedLength,
pokemonsLoadedNames,
getList,
loadPokemon,
loadPokemons
}
})
And I have the following component which makes use of that storage to get the pokemons:
<template>
<div class="pokedex">
<PokemonImage class="pokemon-figure" pokemon="" />
<ul v-if="pokemonsToShow" class="pokemon-showcase">
<li class="pokemon-item" v-for="pokemon in pokemonsToShow">
<PokemonCard :pokemon="pokemon" />
</li>
</ul>
<div class="navigation">
<button v-show="page !== 1" #click="pageChange(-1)">Previous Page</button>
<button #click="pageChange(1)">Next Page</button>
</div>
{{ page }}
</div>
</template>
<script setup>
import { onBeforeMount, ref, computed, watch } from 'vue';
import { usePokemonStore } from '../stores/pokemon'
import PokemonCard from '../components/PokemonCard.vue'
import PokemonImage from '../components/PokemonImage.vue'
const pokeStore = usePokemonStore();
const page = ref(1)
const pokemonsToShow = ref([])
// offset and limit calculate based on the page
const limit = computed(() => 20 );
const offset = computed(() => page.value * limit.value - limit.value);
// initial load
onBeforeMount(async () => {
await pokeStore.getList()
await pokeStore.loadPokemons(0, limit.value)
pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(0, pokeStore.pokemonsLoadedLength)
})
const pageChange = async (step) => {
page.value = page.value + step
await pokeStore.loadPokemons(offset.value, limit.value)
const start = offset.value;
const end = offset.value + limit.value;
console.log(start, end)
console.log(pokeStore.pokemonsLoaded)
pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(start, end)
console.log(pokemonsToShow.value)
}
</script>
Now when the user clicks on the page button the page.value is updated so that the computed values for the offset and the limit are also updated (in reality only the offset updates) that way if the page is new I can load new pokemons from that which I do by calling the pokeStore.loadPokemons(offset.value, limit.value) function and awaiting for that inside the pageChange function. But now I want to change the pokemonsToShow so I want to get a slice of the array of loaded pokemons in the storage but every time I try to slice that array I get back nothing, even though when I print the array using console.log(pokeStore.pokemonsLoaded) the array shows as updated with the new values, and the ranges are correct.
I'm expecting the array to slice correctly since if I put static values in this function call:
pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(2, 4)
}
It works for some reason, but not with the values calculated dinamically
This is a tricky thing about console.log().
console.log(pokeStore.pokemonsLoaded) will show you the result of the fetched data even if console.log is in reality executed before the fetch is done. This is due to the fact that many browsers show a "live" view of object data.
https://developer.mozilla.org/en-US/docs/Web/API/Console/log#logging_objects
Don't use console.log(obj), use console.log(JSON.parse(JSON.stringify(obj))) ... many browsers provide a live view that constantly updates as values change. This may not be what you want.
It is probable then that the array has not actually been updated at the time you slice it. I also believe this is true because even though you await this call: await pokeStore.loadPokemons(...), that function does not await it's call to loadPokemon(). Since there is no await, the function immediately finishes executing before the fetch has finished and returns to your component code.
I believe if you do await that call, everything should start working
async function loadPokemons(offset, limit){
.
.
.
await loadPokemon(pokemonsList.value[i].name)
}

Use filter in Vue3 but can't read globalProperties

Just a quick question,
I know that Vue3 doesn't use filters anymore and notes says use computed or methd instead. but also there is a globalProperties we can use,
I used this globalProperties but keep getting this error
Uncaught TypeError: Cannot read property 'globalProperties' of undefined
Does anyone know where is the bug in my code?
const app = {
data() {
return {
message: ""
}
}
}
app.config.globalProperties.$filters = {
formatDate(value) {
if (value == "0001-01-01T00:00:00")
return "";
var today = new Date(value);
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
var yyyy = today.getFullYear();
today = dd + '/' + mm + '/' + yyyy;
return today;
}
}
Vue.createApp(app).mount('#app');
And I am using the filter in my table like this
<td>
{{ $filters.formatDate(incident.incidentData) }}
</td>
The config field belongs to the root instance not to the root component so you should do:
const app = {
data() {
return {
message: ""
}
}
}
const myApp=Vue.createApp(app)
myApp.config.globalProperties.$filters = {
formatDate(value) {
if (value == "0001-01-01T00:00:00")
return "";
var today = new Date(value);
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
var yyyy = today.getFullYear();
today = dd + '/' + mm + '/' + yyyy;
return today;
}
}
myApp.mount('#app');
Vue.createApp(app) return the root instance
myApp.mount('#app'); after mounting root app to an element it returns the root component

How to use Mixin in main.js in Vuejs?

I am trying to use global information from a mixin. I intend to access the getNow computed prop in a component, but it seems to be undefined.
main.js:
Vue.mixin({
data: function() {
return {
chainBoxURL: "http://172.22.220.197:18004/jsonrpc"
}
},
computed: {
getNow() {
const today = new Date();
const date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
const time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
const dateTime = date + ' ' + time;
return dateTime;
}
}
})
Component:
methods: {
getChainAddress(form) {
if (form.password == form.password_again && form.password != '') {
console.log(this.getNoW)
}
}
}
Seems like there is a typo in when you try to access getNow, there is a W instead of a w.
Side notes,
You could use template strings to make life slightly easier
const today = new Date();
const date = `${today.getFullYear()}-${(today.getMonth() + 1)}-${today.getDate()}`;
const time = `${today.getHours()}:${today.getMinutes()}:${today.getSeconds()}`;
const dateTime = `${date} ${time}`;
You can flip your conditions within the if statement as JS won't evaluate the 2nd one if the first one is false in case of an &&
if (form.password != '' && form.password == form.password_again) {
console.log(this.getNoW)
}
The computed prop in the mixin is defined as: getNow() but youn spelt it as getNoW() within the component.
Either that or you may have forgot to include the mixin in the component.

Subtract 2 times in react-native

I want to subtract two times and check if check_in time > 12Hr then navigate to checkin screen. This is my code snippet
class SplashView extends Component {
componentDidMount() {
const curr_time = moment().format('hh:mm:ss');
const checkin_time = moment(this.props.datetime).format('hh:mm:ss');
// const diff = moment.duration(checkin_time.diff(curr_time));
console.log("TIME&&&&&&&&", curr_time, checkin_time);
setTimeout(() => {
if (this.props.employee_id === null) {
this.props.navigation.navigate('Login');
} else {
this.props.navigation.navigate('Checkin');
}
}, 1000)
}
render() {
return ();
}
}
I'm using moment.js and the value of this.props.datetime is '2019-02-04 14:52:01'. This is my checkin time.
You can get the difference in hours like this:
const diff = moment.duration(checkin_time.diff(curr_time)).as('hours');
Or you can just use moment's diff function
const diff = checkin_time.diff(curr_time, 'hours')
and then compare if (diff > 12) { ... }

Restrict date in jquery datetimepicker based on another datetimepicker

I have two text boxes with a datetimepicker hooked up to them. The text boxes are for start date and end date. The first datetimepicker is setup so that the user cannot choose a date before today, but can choose any date in the future.
How can I setup the second datetimepicker so that it cannot choose a date before the date chosen in the first date picker and whatever date is selected in first datetimepicker, the second datetimepicker date should be exactly 1 month from the first datetimepicker(User can then select the second datetimepicker to be 1 month or less than 1 month)?
Here's what I have so far:
Tried it via datetimepicker and onChangeDateTime function
<script src="~/Scripts/jquery.datetimepicker.js"></script>
<script>
$(document).ready(function () {
$('#ValidFrom').datetimepicker({
datepicker: true,
timepicker: false,
format: 'm/d/Y',
step: 30,
minDate: new Date(),
onChangeDateTime: function (dp, $input) {
var date = new Date($input.val());
$('#ValidTo').datetimepicker("option", "minDate", date);
//alert(date);
var date2 = new Date($input.val());
date2.setMonth(date.getMonth() + 1);
$('#ValidTo').datetimepicker("option", "maxDate", date2);
//alert(date2);
date2 = (date2.getMonth() + 1) + '/' + date2.getDate() + '/' + date2.getFullYear();
$('#ValidTo').val(date2);
}
});
$('#ValidTo').datetimepicker({
datepicker: true,
timepicker: false,
format: 'm/d/Y',
step: 30,
minDate: new Date()
});
});
</script>
If today is 1/16/2019 and I choose 1/28/2019 in the first datetimepicker, then the second date picker shouldn't be able to choose anything before 1/28/2019, second datetimepicker date should be 2/28/2019 or the user if wants, can select the date as less than 1 month.
You can use this function and use startdate id as date_timepicker_startend and enddate id as date_timepicker_end
<input type="text" class="form-control" id="date_timepicker_start">
<input type="text" class="form-control" id="date_timepicker_end">
These are the plugins you have to call
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.full.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.min.js"></script>
Date Logic with date and time validation
jQuery(function(){
var logic_start = function( currentDateTime ){
var d = new Date(currentDateTime); var date = d.getDate();
var month = d.getMonth(); var year = d.getYear();
var hours = d.getHours(); var minutes = d.getMinutes();
var dd = new Date($('#date_timepicker_end').val()); var end_date = dd.getDate();
var end_month = dd.getMonth(); var end_year = dd.getYear();
var end_hours = dd.getHours(); var end_minutes = dd.getMinutes();
var endtime= end_year+'/'+end_month+'/'+end_date;
var starttime= year+"/"+month+"/"+date;
if(starttime==endtime){
this.setOptions({
maxTime:end_hours+":00"
});
}else
this.setOptions({
maxTime:"23:00"
});
this.setOptions({
maxDate:jQuery('#date_timepicker_end').val()?jQuery('#date_timepicker_end').val():false
});
};
var logic_end = function( currentDateTime ){
var d = new Date(currentDateTime); var date = d.getDate();
var month = d.getMonth(); var year = d.getYear();
var hours = d.getHours(); var minutes = d.getMinutes();
var dd = new Date($('#date_timepicker_start').val()); var end_date = dd.getDate();
var end_month = dd.getMonth(); var end_year = dd.getYear();
var end_hours = dd.getHours(); var end_minutes = dd.getMinutes();
var starttime= end_year+'/'+end_month+'/'+end_date;
var endtime= year+"/"+month+"/"+date;
if(starttime==endtime){
this.setOptions({
minTime:end_hours+":00"
});
}else
this.setOptions({
minTime:"00:00"
});
this.setOptions({
minDate:jQuery('#date_timepicker_start').val()?jQuery('#date_timepicker_start').val():false
});
};
jQuery('#date_timepicker_start').datetimepicker({
format:'Y/m/d H:i:s',
onChangeDateTime:logic_start,
onShow:logic_start
});
jQuery('#date_timepicker_end').datetimepicker({
format:'Y/m/d H:i:s',
onChangeDateTime:logic_end,
onShow:logic_end
});
});
let DateInitial = $("#DateInitial");
let DateEnd = $("#DateEnd");
let dateNow = new Date();
/* click start clear end */
DateInitial.on("click", function(){
DateEnd.val(" ");
DateInitial.datetimepicker({
onShow:function( ct ){
this.setOptions({
format: 'd-m-Y H:i',
closeOnDateSelect : true,
validateOnBlur : true,
minDate: -0,
minTime: dateNow.getTime(),
onClose: function($input){
dateAllowPlusOne($input);
}
});
}
});
});
function dateAllowPlusOne(dateStart){
if(DateInitial.val()=="")
{
DateInitial.focus();
return false;
}
DateEnd.datetimepicker({
'format': 'd/m/Y H:i',
'minDate': -0,
startDate: dateStart,
'closeOnDateSelect' : true,
'validateOnBlur' : true,
'minDateTime': new Date()
});
DateEnd.attr("disabled", false);
}