Step bar load with animation - vue.js

Here is my progress bar from Vue bootstrap components, you can set default number in data with value: number, I want it to increase it automatically whenever I go to next page. Can anyone assist me with this? I tried with props but I have no idea how to do it.
b-progress(:value='value', :max='max', show-progress='', animated='')
b-button.next.mt-3.pb-1(v-if="nextLink" :to="{name: nextLink}")
RegistrationNav(prev-link="registration_goal" next-link="registration_interview")

For a basic example, without using vue lets imagine this way:
You have a parent component that includes the b-progress and some other component or inout for the user:
<template>
<div>
<b-progress :value="currentValue"><b-progress/>
<button #click="currentValue++">Click to increment </button>
</div>
</template>
export default {
name: "Login.vue",
data() {
return {
currentValue: 1
}
}
}

Related

How to change the language of whole application from the dropdown in Navbar component in vue

I created a language selection dropdown in my Navbar component. So here is my navbar component:
<div>
<h6>{{ translate("welcomeMsg")}} </h6>
<select name="lang" v-model="lang">
<option value="en">English</option>
<option value="de">Deutsch</option>
</select>
</div>
<script>
export default {
mixins: [en, de],
data() {
return {
lang: "en",
};
},
methods: {
translate(prop) {
return this[this.lang][prop];
}
}
}
</script>
So the parent of this component is an Index.vue which is main component in my application.
<div id="app">
<Topnav/>
<Navbar/>
<router-view></router-view>
<Footer/>
</div>
Currently, I am able to change the language in my Navbar component. So according to the selected value in the dropdown in Navbar component, welcomeMsg is changing. What I am trying to do is I want to put this pieve of code to TopBar "{{ translate("welcomeMsg")}} ", and according to the value of the dropdown in Navbar component, I want to change this value.
Can you help me with this or can you give me an idea how to do it?
If I understand you correctly, you want to use translate method inside Topnav component.
This method is however defined in Navbar, so it's not accessible in Topnav.
To use it elsewhere you could create a mixin with this method to import it to any component. I don't recommend this solution though as mixins are making the code messy.
Another solution is to create a component with translate method defined inside. Let this component do just that: translate a message passed by prop and render it inside some div:
<div>
{{ translatedMessage }}
</div>
<script>
mixins: [en, de],
props: {
message: {
type: String,
default: ''
},
language: {
type: String,
default: 'en'
}
},
computed: {
translatedMessage() {
return this[this.language][this.message];
}
}
</script>
You can reuse this component anywhere in the application. You would still need to pass a language prop somehow, possibly the solution would be to use vuex store to do this, since language is probably global for entire application.
For easier and more robust solutions I would use vue-i18n, which #Abregre has already suggested in his comment: https://stackoverflow.com/a/70694821/9463070
If you want a quick solution for a full-scale application and you don't have a problem with dependencies, you could try to use vue-i18n.
It's a plugin for vue that does exactly this for multi-locale websites/apps in Vue.
https://www.npmjs.com/package/vue-i18n
EDIT
Then in order to use it globally in your app, you should use vuex.
Keep the language selection state there and then wherever you want to use it, you make a computed function with the state.language getter.
The translate function should be a global registered filter
https://v2.vuejs.org/v2/guide/filters.html

Vue: Reuse loading spinner template and logic

I've multiple (20+) pages where I need the following code:
<template>
<template v-if="isLoading">
<Spinner full size="medium" />
</template>
<template v-else>
<p>Page data</p>
</template>
</template>
<script>
export default {
computed: {
isLoading() {
return this.$store.getters['loader/isLoading'];
},
},
};
</script>
I don't want to rewrite this part everytime I need it so is there a way to create something like a higher order component with access to the computed method and a way to add the hoc to the script tag of the different vue files? Or another way to archive this?
I could recommend extending the spinner component where you want to show the spinner. I've created a boilerplate setup that show a very simple implementation of this approach here.
The main idea is to expose a default slot for you spinner component, and wrap the page component in that slot.
<template>
<div>
<Spinner v-if="isLoading" full size="medium" />
<!-- Slot for component data -->
<slot v-else></slot>
</div>
</template>
<script>
export default {
computed: {
isLoading() {
return this.$store.getters['loader/isLoading'];
},
},
};
</script>
Then in any component that you want to show the spinner:
<template>
<spinner>
<!-- Pass here the component content to be shown after the spinner is hidden -->
</spinner>
</template>
<script>
import Spinner from "./spinner";
export default {
name: "Page1",
extends: Spinner,
components: { Spinner }
};
</script>

How can i just have one Component instead of different components in the context of Vuejs

I am new to Vuejs, I am using 4 different components, where in every component i have called the API. Here 4 different components are all same except their contents.
Now, i want to make my code effective, so i want to have a single component, the reason why i created different components is my another App.vue component has 4 different buttons, so whenever you click any of it, it will open the respective component.
But now i want to have only one component instead of four different components, and whenever the buttons in App.vue component is clicked it should open the exact content in single component(instead of 4 components).
Please do help me with this, by sharing your ideas and if any examples.
In this context, you can use props, which is a way of passing data to "child" components.
https://v2.vuejs.org/v2/guide/components-props.html
Example
App.vue
<template>
<div id="app">
<SingleComponent :button="button" />
</div>
</template>
<script>
import SingleComponent from "#/components/SingleComponent.vue";
// #/ means src/
export default {
name: "App",
components: {
SingleComponent,
},
data: () => ({
button: 2,
}),
};
</script>
SingleComponent.vue
<template>
<div>
<button v-if="button === 0">...</button>
<button v-else-if="button === 1">...</button>
<button v-else-if="button === 2">...</button>
<button v-else-if="button === 3">...</button>
</div>
</template>
<script>
export default {
name: "SingleComponent",
props: {
button: {
type: Number,
required: true,
},
},
};
</script>
You should also take a look at slots, it is very important in Vue.js and that could also solve your problem.
https://v2.vuejs.org/v2/guide/components-slots.html

Vue - passing a variable as a component prop

I'm new to vue and I downloaded this Pomodoro timer component for my app (https://github.com/P3trur0/vuemodoro) which works well, except the time isn't adjustable inside the app itself.
Im trying to make an input field where the number of minutes will be entered and passed to the pomodoro timer, using the built in "minutes" property, but I don't understand how or if it's possible to pass variables to component properties in this way.
'''
<div>
<b-field class="timer">
<b-numberinput v-model="number"></b-numberinput>
</b-field>
<Pomodoro :minutes="1"/>
</div>
'''
Okay, so it seems that the Pomodoro component does not support reactive properties, so, while the timer will correctly be set to the initial value of number, it will not update if number changes. But - don't worry - there's an easy way around this: setting a key to the timer:
<Pomodoro :key="number" :minutes="number" />
A key tells Vue to update the component when the key has changed, so, in this case, whenever number changes, the Pomodoro element will be updated. More info on keys here.
Without a key:
With a key:
This is the full code:
<template>
<div id="app">
<b-field class="timer">
<b-numberinput v-model="number"></b-numberinput>
</b-field>
<Pomodoro :key="number" :minutes="number" />
</div>
</template>
<script>
import Pomodoro from "vuemodoro";
export default {
name: "App",
data() {
return {
number: 0,
};
},
components: {
Pomodoro,
},
// rest of the component
};
</script>
Also, you can try out this demo, and view/edit the code behind it

What is the correct way to retrieve data from 2 or more identical components?

Evening. I've created a button which adds a component that has an input field inside. I might need to press that button few times so there would be 2-3 input fields that appear. Whenever I type the text I would like to send a request from the parent component but I don't know how to retrieve the data from every child component that has been created. Is this the time to start using vuex (never used it)?
ParentComponent.vue
<template>
<div>
<button class="btn btn-success" #click="addStep">Add step</button>
<div v-for="i in count">
<recipe-step v-bind:step-number="i"></recipe-step>
</div>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
addStep() {
this.count += 1;
}
}
}
</script>
StepComponent.vue
<template>
<div>
<div class="from-group">
<label for="step-input"></label>
<input id="step-input" v-model="text" type="text">
</div>
</div>
</template>
<script>
export default {
props: {
stepNumber: {
type: Number,
required: true
}
},
data() {
return {
step: this.stepNumber,
text: ""
}
}
}
</script>
No, you really don't need Vuex yet. As long as you are still dealing with parent-child-component communication, you should be fine. Vuex comes into play when components, spread across the hole component hierarchy, need to exchange information.
Now, you should do something like this:
Don't store the text in the child component. When the input changes, send a Custom Event right to the parent component. Note that
<input v-model="text">
is only syntax sugar for
<input :value="text" #input="text = $event">
Both have the same effect. That's way you can send the input event up to the parent, like this:
<input #input="$emit('input', $event)">
Add another prop to your child component called value which should replace text.
And now you can use v-model in the parent component:
<recipe-step v-model="text">
To store multiple values, just use an array in your data properties.
<recipe-step v-model="textArray[i]">
Vuex can help you on that, however if all you want is to get the input text value back to the parent with the minimum effort you can create a prop called value in the children and then pass it as v-model in the parent.
Since you have a v-for you could make it iterate over a list instead a counter and then pass some prop inside each item as v-model