Vue.js Digest 🇷🇺 🇺🇸
38 subscribers
389 photos
745 links
Дайджест новостей из мира vuejs
Download Telegram
How to create dynamic input using Vue

https://dev.to/snehalk/how-to-create-dynamic-input-using-vue-2hf7
Hello Readers,
In this blog, I am going to show you, how we can create dynamic input using vuejs.
First, create a component and name it as DynamicInput.vue and add the below code.



<template>
<div class="hello">
<h1>{{ msg }}</h1>
<div class="w-full mt-4 p-10">
<button
type="button"
class="flex justify-start ml-2 rounded-md border px-3 py-2 bg-pink-600 text-white"
@click="addMore()"
>
Add More
</button>
<div v-for="(course, index) in courses" :key="index">
<div class="flex justify-start ml-2 mt-4">
<input
v-model="course.courseName"
class="w-full py-2 border border-indigo-500 rounded"
/>
<button
type="button"
class="ml-2 rounded-md border px-3 py-2 bg-red-600 text-white"
@click="remove(index)"
v-show="index != 0"
>
Remove
</button>
</div>
</div>
</div>
</div>
</template>

<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
data() {
return {
courses: [
{
courseName: "",
},
],
};
},
methods: {
addMore() {
this.courses.push({
courseName: "",
});
},
remove(index) {
this.courses.splice(index, 1);
},
},
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>


Now add this component into App.vue file as below.



<template>
<div id="app">
<DynamicInput msg="Example of Dynamic Input" />
</div>
</template>

<script>
import DynamicInput from "./components/DynamicInput";
export default {
name: "App",
components: {
DynamicInput,
},
};
</script>

<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>


I have installed tailwind CSS to styling you have to install it.
If you like my post please follow me to get more blog posts.


.ltag__user__id__672647 .follow-action-button {
background-color: #9f0b46 !important;
color: #ffffff !important;
border-color: #9f0b46 !important;
}








Snehal Follow


Software Developer by Profession, mostly works in Laravel | Vue JS | Nuxt JS | PHP | Javascript | InertiaJS.



For more details you can refer below codesandbox.



Happy Reading. 🦄 ❤️
Global State Management in an Electron Application

https://dev.to/codybontecou/global-state-management-in-an-electron-application-n3f
Global State Management in an Electron Application using Pinia and VueJS


Bringing the VueJS tool Pinia into our Electron application to manage its internal state. This post assumes you have followed along with my previous post.




What is a Store?

A Store is an entity that manages the global state of your application. It allows you to read and write to, regardless of the component you are working within.
You may have heard of other packages that help manage a store, Vuex is the standard for Vue and Redux is the standard for React.



Installation


This assumes you are using Vue 3. \

If you are using Vue 2, please refer to their documentation.

Because we are hooking this up to an Electron application, which is just Javascript with extra steps, we can utilize our favorite package manager such as npm or yarn to install Pinia.



yarn add pinia
# or with npm
npm install pinia


Use the createPinia function to attach it to the VueJS app:



// renderer/main.js
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
createApp(App).use(createPinia()).mount('#app')


Pinia is now available throughout your Electron application where Vue is available.



Creating our first store

A store is defined using defineStore() and requires a unique name. In this case, I am using main as the unique id attached to this store.



// renderer/stores/main.js
import { defineStore } from 'pinia'
// useMainStore could be anything like useUser, useCart
// the first argument is a unique id of the store across your application
export const useMainStore = defineStore('main', {
state: () => ({
msg: 'Hello World!',
}),
getters: {
message: state => state.msg,
},
actions: {},
})





Using our store within a VueJS component

Now that our store is made, we can import it into individual components, allowing our components to interact with the store.



import { useMainStore } from '@/stores/main'


Within the setup function, I call our store function and set the value within a const variable:



setup() {
const main = useMainStore()
}


This allows me to interact with my store. For this simple example, I am displaying the message defined within the getter.



setup() {
const main = useMainStore()
return {
message: computed(() => main.message),
}


The entire component can be seen below:



// renderer/components/Hello.vue
<template>
<div id="hello">
<img src="https://vuejs.org/images/logo.png" />
<h1>{{ message }}</h1>
</div>
</template>
<script>
import { computed, defineComponent } from 'vue'
import { useMainStore } from '@/stores/main'
export default defineComponent({
setup() {
const main = useMainStore()
return {
message: computed(() => main.message),
}
},
})
</script>





Getting HMR to work


While HMR is built into Pinia, it doesn't play well with Electron and requires a bit of additional configuration.

Pinia provides additional documentation of this topic here.

HMR (Hot Module Replacement) allows you to edit your stores and see the changes within your app without having to reload the page or restart your server.
Here's what my main store looks like after updating it to allow for HMR:



import { defineStore, acceptHMRUpdate } from 'pinia'
export const useMainStore = defineStore('main', {
state: () => ({
msg: 'Hello World!',
}),
getters: {
message: state => state.msg,
},
actions: {},
})
if (import.iss.oneta.hot) {
import.iss.oneta.hot.accept(acceptHMRUpdate(useMainStore, import.iss.oneta.hot))
}


Passing acceptHMRUpdate your store (useMainStore in my case), it gives us HMR!
Hope you enjoyed!
💡 Vue Typescript State Management : We can do better than “isLoading” in 2022

https://dev.to/monisnap/vue-typescript-state-management-we-can-do-better-than-isloading-in-2022-2n5d
Sorry for the clickbait title, but I needed your attention 👀 
Have you ever encountered code like this one :



new Vue({
el: '#app',
data () {
return {
info: null,
loading: true,
errored: false
}
},
filters: {
currencydecimal (value) {
return value.toFixed(2)
}
},
mounted () {
axios
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => {
this.info = response.data.bpi
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
}
})
...
<div id="app">
<h1>Bitcoin Price Index</h1>
<section v-if="errored">
<p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
</section>
<section v-else>
<div v-if="loading">Loading...</div>
<div
v-else
v-for="currency in info"
class="currency"
>
{{ currency.description }}:
<span class="lighten">
<span v-html="currency.symbol"></span>{{ currency.rate_float | currencydecimal }}
</span>
</div>
</section>
</div>


It’s an example I found in the Vue documentation here https://vuejs.org/v2/cookbook/using-axios-to-consume-apis.html#Dealing-with-Errors
What if you have multiple things that could load, do you add a loading2 variable ? 👀
To solve this issue, you can use a variable for each async actions you have with this 4 “states” :

IDLE : the user didn’t trigger the action yet
WAITING : the action is ongoing
ERROR : there was an error
DONE : The action succeeded

Using an enum with the different states, and better naming, the code can be rewritten like this :



enum AsyncState {
IDLE = 'IDLE',
WAITING = 'WAITING',
ERROR = 'ERROR',
DONE = 'DONE',
}
new Vue({
el: '#app',
data () {
return {
info: null,
AsyncState,
currentPriceLoadState: AsyncState.WAITING,
}
},
filters: {
currencydecimal (value) {
return value.toFixed(2)
}
},
mounted () {
axios
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => {
this.info = response.data.bpi
this.currentPriceLoadState = AsyncState.DONE
})
.catch(error => {
console.log(error)
this.currentPriceLoadState = AsyncState.ERROR
})
}
})
...
<div id="app">
<h1>Bitcoin Price Index</h1>
<div v-if="currentPriceLoadState === AsyncState.WAITING">Loading...</div>
<section v-else-if="currentPriceLoadState === AsyncState.ERROR">
<p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
</section>
<section v-else>
<div v-for="currency in info" class="currency">
{{ currency.description }}:
<span class="lighten">
<span v-html="currency.symbol"></span>{{ currency.rate_float | currencydecimal }}
</span>
</div>
</section>
</div>


With better naming and this simple enum, you can almost cover all the use cases where you need to load one or multiple things and manage errors
If you want to manage different error messages, you can add another variable with an enum type like this :



enum CurrentPriceLoadErrors {
INVALID_CURRENCY = 'INVALID_CURRENCY',
API_LIMIT_REACHED = 'API_LIMIT_REACHED',
DEFAULT = 'DEFAULT',
}


Tell me in the comment section if you like this trick or not, and if you have an even better technique !
And don’t forget to like and share this post if you liked it 💙
Hello world in Vue.js

https://dev.to/mohsenkamrani/hello-world-in-vuejs-3l1
So you've heard the name Vue.js, at least I assume so otherwise you wouldn't be here. Also you might have heard how powerful, yet simple it is. In this post, which is the first on in a series of posts about Vue.js, I'll show you the basic steps to get started with Vue.js, and print the message we all look forward to seeing, the glorious "Hello, world!".
Let's start by creating a file named index.html and import Vue in the head tag like this:



<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
...


Now that we can use Vue, let's use Vue's template syntax to render our message:



<body>
<div id="app">{{ message }}</div>
</body>


Notice that here we have a special syntax which is different from our usual html: {{ message }}. Here we are just rendering the value of variable named message exactly where the template is placed.
All we need to now is to create an instance of Vue and attach it to our HTML tag. To reference the tag I've given it an arbitrary id app. Let's do this by creating a file named index.js:



var app = new Vue({
el: '#app',
data: {
message: 'Hello, world!'
}
})


In this code we have created a new instance of Vue, have specified an element to attach to, and the data that is available to be used in our templates.
It's worth mentioning that #app refers to an html element with the id of app.

As the last step we just import index.js lin our html page. Just make sure you import it right before your closing body tag.



<script src="./index.js"></script>
</body>


This is all we need to render our message with Vue and this is how our complete index.html looks like:



<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">{{ message }}</div>
<script src="./index.js"></script>
</body>
</html>


Now that we have our code ready, let's deploy it on utopiops.
Head over to the Fully managed applications section as we want to use free static website deployment and hosting that Utopiops offers.

Now we choose Static website as the application type to be created. (Utopiops also offers free plans for Function and Dockerized applications)

Now the only thing we need to know is to specify the repository that we store our code (Utopiops supports Github, Bitbucket and Gitlab).
Remember we don't need to provide any build command!

And that's it, in a few seconds we have our website ready and every time we make a change to our code it automatically deploys our changes.
https://vuejs-hello-world-e9d16563.sites.utopiops.com
Note: Utopiops is in public beta at the time of writing this post and the view you see when you log in to Utopiops at https://www.utopiops.com might be different, but the good news is that it sure just have become more user-friendly and easier to use.
You can find the source code here.
Conditionals and loops in Vue.js

https://dev.to/mohsenkamrani/conditionals-and-loops-in-vuejs-imn
In my previous post I covered the basics of using Vue in our web application. In this tutorial I will cover two of the most important feature or fundamental structures of Vue, conditionals and loops. It's worth mentioning as we go towards more advanced topics in the upcoming blogs we'll use what we learned in the previous tutorials to solve more complex problems. For now, let's keep it short and simple.
Let's again start by creating a file named index.html and import Vue in the head tag like this:



<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
...


Now we want to conditionally render a tag based on a random value. Let's say we have a tag like this:



<div>I'm displayed randomly</div>


To do so let's create a file named index.js and create an instance of Vue.



var app = new Vue({
el: '#app'
})


We want to attach this instance to an element with id app so let's wrap our dynamically rendered code inside a div and give it the id app



<div id="app">
<div>I'm displayed randomly</div>
</div>


Now we add a boolean property to our instance and set its value randomly to true or false:



var app = new Vue({
el: '#app',
data: {
random: Math.random() > 0.5,
}
})


And we use a directive named v-if to render the div only if random is true:



<div id="app">
<div v-if="random">I'm displayed randomly</div>
</div>



The directive v-if is used to conditionally render a block. The block will only be rendered if the directive’s expression returns a truthy value.

Matho.random() generates a number between 0 and 1, so we expect almost half of the times we refresh the page, we see the message.
Next, let's render a list of colours with v-for directive. We add an array containing such names to our vue instance first.



var app = new Vue({
el: '#app',
data: {
random: Math.random() > 0.5,
colours: ["red", "blue", "black", "green"]
}
})


Now we can simply use v-for to render the list:



<ol>
<li v-for="colour in colours">
{{colour}}
</li>
</ol>



We can use the v-for directive to render a list of items based on an array. The v-fordirective requires a special syntax in the form of item in items, where items is the source data array and item is an alias for the array element being iterated on.

Finally this is how our index.html file looks like:



<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-if="random">I'm displayed randomly</div>
<ol>
<li v-for="colour in colours">{{colour}}</li>
</ol>
</div>
<script src="./index.js"></script>
</body>
</html>


Now that we have our code ready, let's deploy it on utopiops.
Head over to the Fully managed applications section as we want to use free static website deployment and hosting that Utopiops offers.

Now we choose Static website as the application type to be created. (Utopiops also offers free plans for Function and Dockerized applications)

Now the only thing we need to know is to specify the repository that we store our code (Utopiops supports Github, Bitbucket and Gitlab).
Remember we don't need to provide any build command!

And that's it, in a few seconds we have our website ready and every time we make a change to our code it automatically deploys our changes.
https://vuejs-conditional-loops-bd885053.sites.utopiops.com
Note: Utopiops is in public beta at the time of writing this post and the view you see when you log in to Utopiops at https://www.utopiops.com might be different, but the good news is that it sure just have become more user-friendly and easier to use.
You can find the source code here.
Nuxt 3 + Apollo Client

https://dev.to/joshwcorbett/nuxt-3-apollo-client-h6
If you're working on a Nuxt 3 project, and trying to get Apollo up and running, only to find that the nuxt module isn't updated yet for v3, then follow along.
As of late 2021 and early 2022, the Nuxt Community Apollo module is still in limbo for an update to play along with Nuxt 3, and I'm not patient enough to wait many more months for that. The question of why I'm bothering with Nuxt 3 this early on, is irrelevant, I merely just want to play around with it.
This is an extremely minimal demonstration, and should by no means be used for production without extra configuration.
Assuming you already have a Nuxt 3 project ready, let's move on to step 1.



Part 1: Installing the Dependencies

We'll use both @apollo/client and vue-apollo which is updated to work with Vue 3, and therefore willl work fine inside our Nuxt 3 project.



yarn add vue-apollo @apollo/client graphql





Part 2: Creating the Plugin

If you don't already have a plugin folder in your root directory, make one and create a js file inside to represent your Apollo Client



root/
- components/
- api/
- pages/
- plugins/ <--
- apollo-client.js <--
- etc...


apollo-client.js



import { defineNuxtPlugin } from "#app"
import { ApolloClient, InMemoryCache } from "@apollo/client/core"
import { DefaultApolloClient } from "@vue/apollo-composable"
export default defineNuxtPlugin((nuxtApp) => {
const apolloClient = new ApolloClient({
cache: new InMemoryCache()
// configuration //
})
nuxtApp.vueApp.provide(DefaultApolloClient, apolloClient)
})





Part 3: Configuration

To keep things secure, I recommend using environment variables to store your api keys and credentials.
.env



API_ENDPOINT="https://your-api.com"


In our apollo-client.js file, populate your config with



const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
uri: process.env.API_ENDPOINT <-- add your uri
// other configuration
})


You can read up on ways to configure your apollo client here: https://www.apollographql.com/docs/devtools/apollo-config/



Part 4: Nuxt Configuration

Almost nothing needs to be done here, Nuxt automatically imports your javascript files located in the plugins/ folder. We do still need to add to our build config.
In our build config in nuxt.config.js:



build: {
transpile: [
'@apollo/client',
'ts-invariant/process',
],
},


If you do not add @apollo/client and ts-invariant/process into transpile, you will face an error.



Part 5: Using Apollo

I've created a query in our api/folder called queries.js



import { gql } from "@apollo/client/core"
export const GET_POSTS = gql`
query posts {
posts (first: 20) {
id
title
}
}
`


In our Vue file, let's import useQuery from vue-apollo



import { useQuery, useResult } from '@vue/apollo-composable'
import { GET_POSTS } from '@/api/queries'
const { loading, result } = useQuery(GET_POSTS)





Conclusion

This is merely just a minimal demonstration of how to get apollo up and running with your Nuxt 3 project, not a fleshed out or production-ready solution. If you'd like to have a more official solution that doesn't involve creating your own plugin, either wait for Nuxt 3 support on the official Apollo Nuxt Module, or check out this module I found on Github.



Thanks for Reading

I hope this was helpful.
What is the utility of a v-model directive?

https://dev.to/leonnimoy/what-is-the-utility-of-a-v-model-directive-coh
Definition

Looking through the documentation v-model is a directive that can be use to:
"Create a two-way binding on a form input element or a component".
Which in other words, allows you to kinda create a data relation between the data object of your component and some other component or an HTML element, like a form input.



Nice! But why is that useful?

Because allows you to make quick value updates in your component. Without the need to use states, props, or anything like that. And is a "two-way binding", allowing a great manipulation of data in your component.




Example

Let's see a quick example:

HTML:



<div id="app">
<input v-model="checkedNames" type="checkbox" id="kirk" value="John"/>
<label for="kirk"> Kirk</label>
<input v-model="checkedNames" type="checkbox" id="spock" value="Paul"/>
<label for="spock"> Spock</label>
<input v-model="checkedNames" type="checkbox" id="mcCoy" value="George"/>
<label for="mcCoy"> McCoy</label>
<input v-model="checkedNames" type="checkbox" id="uhura" value="Ringo"/>
<label for="uhura"> Uhura</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>


CSS:



body {
font-family: 'Bitter', serif;
}
#app {
text-align: center;
padding: 70px;
max-width: 360px;
font-size: 16px;
margin: 0 auto;
display: table;
line-height: 2em;
}
label {
padding-right: 10px;
}


JavaScript:



const App = {
data() {
return {
checkedNames: []
}
}
}
Vue.createApp(App).mount('#app')


See how in each input tag, the v-model directive manipulates the DOM and appends the value in each label, into the array. From the input to the data component object (one-way biding). And after that, send the array updated with the values to the span tag(two-way biding)?
Awesome, right?




Restrictions

As explained in the documentation, the v-model directive has its use limited to the following elements:



<input>
<select>
<textarea>
components





Acknowledgment

I'll like to thank @sarah_edo, for the great example provided in her CodePen.