Mind Flow Productions

Systems & Productivity

ETR: 6 minutes

Vue Instances

I had some problems with nesting. It turns out vue instances:

Cannot be mounted inside each other. Cannot mount multiple times to different elements. Use components instead.

Many of These tips come from the AMAZING free course on Udemy by Edwin Diaz. I put them here not to rip off his course but as a quick reference for myself as I am coding and learning. Edwin has done an excellent job introducing the core concepts of Vue.js with quick and easy to follow examples. You can code them in real time as you watch the course. Highly recommended! Edwin - if you don’t want me to show this page publicly I can take it down and just use it offline. Just let me know.

https://www.udemy.com/vuejs-fast-crash-course

To play with these tips, create a new folder and in the folder create a new index.html with the following code.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
</head>

<body>
    <div id="app">
    </div>

    <!-- development version, includes helpful console warnings -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">
    </script>

    <script>
        let vm = new Vue({
            el: '#app'
        });
    </script>
</body>
</html>

In a separate command prompt, move into the new folder and start a local server.

For Python3 use:

python -m http.server

It will grab the index.html file and serve it to localhost:8000
Point your browser there to see the code rendered. This is an empty scaffold so you won’t see anything until you add some code from these tips.

Inspecting and changing a Vue Instance

If you assign a new Vue instance to a variable (here it is called vm):

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello',
            isActive: true
        }
    })
</script>

You can then access the vue instance through that variable in the debug console:

vm.message = ‘New Message’

This allows you to change values and see the change in the browser on the fly.

Ternary Operators and Reactivity

Now update the code above to this:

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

    <h1>{{ isActive ? 'is Active' : 'is Not Active' }}</h1>
</div>

These are reactive values so changing them anywhere, including the console, will update the code right away. Browser refresh is not required.

Using anchor tags and passing URLs

<div id="app">
    <a href="{{url}}">{{url}}</a>              <!-- will display the link but it won't work -->
    <a v-bind:href="{{url}}">{{url}}</a>       <!-- still won't work, goes crazy -->
    <a v-bind:href="url">{{url}}</a>           <!-- works! -->
    <a :href="url">{{url}}</a>                 <!-- v-bind shorthand -->
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            url: 'http://rickfalck.com',
        }
    })
</script>

Binding Numeric Data to Attributes

<div id="app">
    <h2 mydata="dynamicId">{{ dynamicId }}</h2>
    <!-- using inspect we see that mydata is assigned the text string "dynamicId" -->
    <!-- in inspect we see <h2 mydata="dynamicId">36</h2>

    <!-- But if we want the numeric value - v-bind to the rescue, using the shorthand : -->
    <h2 :mydata="dynamicId">{{ dynamicId }}</h2>
    <!-- in inspect we see <h2 mydata="36">36</h2>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            dynamicId: 36,
        },
    });
</script>

Two-Way Data Binding

Directives are attributes with some type of behind the scene functionality

v-model is a Vue directive that handles two-way data binding

<div id="app">
  <form action="">
    <div class="field">
      <div class="control">
          <!-- v-model creates two way data binding -->
          <input v-model="message" type="text" class="input is-primary" placeholder="enter something">
      </div>
    </div>
  </form>

  {{message}}  <!-- whatever is typed into the input instantly shows here too -->

</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            // changing this will change the message value anywhere
            message: 'Vue is Awesome!'
        },
    });
</script>

Even changing the value of the message variable from the console will change the message value everywhere it is referenced.

Event Binding

The v-on directive binds to events.

<div id="app">
    <h2 v-on:click="number++">{{ number }}</h2>   <!-- increment with each click -->
    <h2 v-on:click="number--">Decrease</h2>   <!-- decrease with each click -->

    <!-- The @ symbol is shorthand for v-on: -->
    <h2 @click="number++">{{ number }}</h2>
    <h2 @click="number--">Decrease</h2>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            number: 10,
        },
    });
</script>

Directive Modifier

<div id="app">
    <h2 @click="number++">{{ number }}</h2>
    <h2 @click="number--">Decrease</h2>

    <!-- @submit.prevent prevents the normal action of submit 
         which includes a page refresh which we do not want 
    -->
    <form action="" @submit.prevent="number++">
        <button type="submit">Increase</button>
    </form>
    {{ number }}
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            number: 10,
        },
    });
</script>

Dynamic Inline Style Binding

Keep in mind the style names are from javascript, not css. The case is different.

<div id="app">
    <div :style="{color:'red', fontSize:fontSize + 'px'}">{{ message }}</div>

    <!-- pass in an object of styles -->
    <div :style="styleObject">{{ message }}</div>

    <!-- pass in a list of style objects (the last has precedence) -->
    <div :style="[styleObject, styleObject2]">{{ message }}</div>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello',
            fontSize: 30,
            styleObject: {
                color: 'blue',
                fontSize: '10px'
            },
            styleObject2: {
                color: 'green',
                fontSize: '100px'
            }
        },
    });
</script>

Dynamic Style Class Binding

This is so cool!

This works by adding and removing the dynamic classes from the class attribute.

<style>
  .active { color: green; }
  .notActive { color: red; }
</style>

<div id="app">
    <!-- class static does not exist, if thats the only class the color is black (default) -->
    <!-- if class exists, :class appends to it. Otherwise it creates it -->
    <!-- changing the value of isActive changes the font color by changing the class dynamically -->
    <h2 class="static" :class="{active: isActive, 'notActive': !isActive}">{{ name }}</h2>

    <!-- this works by truth values and by precedence - notActive will override active if hasError is true -->
    <h2 :class="{active: isActive, 'notActive': hasError}">{{ name }}</h2>

    <!-- using a ternary operation instead, cleaner code I think -->
    <h2 :class="[isActive ? 'active' : 'notActive']">{{ name }}</h2>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            name: 'Rick',
            isActive: false,
            hasError: true,
        },
    });
</script>

Event Binding Styles

Very Cool! Should be obvious what’s going on here…

<div id="app">
    <button @click="increaseFont">Increase</button>
    <button @click="decreaseFont">Decrease</button>

    <!-- these style names are from javascript, not css. The case is different -->
    <div :style="{color:'red', fontSize:fontSize + 'px'}">{{ message }}</div>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello',
            fontSize: 12,
        },
        methods: {
            // increaseFont: function() {      // older format
            increaseFont() {
                this.fontSize++;
            },
            decreaseFont() {
                this.fontSize--;
            }
        }
    });
</script>

Conditional Rendering

Obviously Cool…

<div id="app">
    <h2 v-if="isActive">{{ name }}</h2>
    <h2 v-else-if="name === 'Rick Falck'">Hey Rick, What's up?</h2>
    <h2 v-else>No ones Home...</h2>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            name: 'Rick Falck',
            isActive: false,
        }
    });
</script>

List Rendering

<div id="app">
    <ul>
        <li v-for="post in posts" :key="post.id">{{post.title}}</li>
    </ul>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            posts: [
                {id: 1, title: 'Post 1', body:'This is a new blog post'},
                {id: 2, title: 'Post 2', body:'This is blog post #2'},
                {id: 3, title: 'Post 3', body:'This is a blog post'},
                {id: 4, title: 'Post 4', body:'This is blog post 4'},
            ]
        }
    });
</script>

Computed Property

<div id="app">
   <!-- this is a dynamic property -->
   <h1>{{ message.split('').reverse('').join('') }}</h1>

   <!-- this is a computed property -->
   <h1>{{ reverseMessage }}</h1>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello'
        },
        computed: {
            reverseMessage() {
                return this.message.split('').reverse('').join('');
            }
        }
       });
</script>

Watchers

<div id="app">
   <h1>Rick Falck is {{ isActive === 'active' ? 'Active' : 'Not Active'}}</h1>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            isActive: 'not active'
        },
        watch: {
            // The value of the variable being watched can be passed to the function (optional)
            isActive: function(updatedValue) {
                console.log('Sending email' + ' ' + updatedValue);
            }
        }
    });
</script>

Intro to Components

The component name becomes the name of the html tag with the built-in functionality of the component.

<div id="app">
   <posts></posts>

   <h2>{{message}}</h2>
</div>

<script>
    Vue.component('posts', {
        template: `<h2>Hello</h2>`
    });

    let vm = new Vue({
        el: '#app',
        data: {
            message: 'This is a message'
        }
    });
</script>

Component with Inline Template

<div id="app">
   <posts inline-template>
     <h2>Hello</h2>
   </posts>
</div>

<script>
    Vue.component('posts', {
    });
    let vm = new Vue({
        el: '#app'
    });
</script>

Component with Click Event

<div id="app">
   <posts inline-template>
     <h2 @click="display">HELLO</h2>
   </posts>
</div>

<script>
    Vue.component('posts', {
        data() {
              return {
              }
        },
        methods: {
            display() {
                console.log('hello');
            }
        }
    });

    let vm = new Vue({
        el: '#app'
    });
</script>

Can also be coded like this:

<div id="app">
   <posts></posts>
</div>

<script>
    Vue.component('posts', {
        template: `
             <h2 @click="display">{{message}}</h2>
        `,
        data() {
              return {
                  message: 'Hello Rick'
              }
        },
        methods: {
            display() {
                console.log('hello');
            }
        }
    });

    let vm = new Vue({
        el: '#app'
    });
</script>

Getting Outside Data with Properties

You have data in an HTML tag attribute and you want to see it inside your component. This is where v-bind with props comes to the rescue. Props connect to attributes so you can access the attribute value inside your component.

<div id="app">
   <posts :mydata="34"></posts>
</div>

<script>
    Vue.component('posts', {

        props: [
            'mydata'
        ],

        template: `
          <div>
            <h2>Inside posts Template</h2>
            <h2 @click="display">{{mydata}}</h2>
            <h2>{{message}}</h2>
          </div>
        `,

        data() {
            return {
                message: 'Hello Rick'
            }
        },

        methods: {
            display() {
                console.log('hello');
            }
        }
    });

    let vm = new Vue({
        el: '#app'
    });
</script>

Nesting Components

The post component is nested inside the posts component. It uses slots to let vue know you want to place the data between a specific begin and end tag in your nested component. Without the &ltslot&gt tag inside the &ltli&gt tag, the &ltpost&gt component would not know to place that data between its start and end tag. It can get a little confusing using the same names for components and for data, but it does not confuse Vue.

It basically means that the data from {{post.title}} is passed into the post component and placed where the slot tag is inside the li tag. Otherwise you caould put any text inside the li tag and that data would be rendered, instead of the from {{post.title}}.

    <div id="app">
       <posts></posts>
    </div>

    <script>
        Vue.component('post', {
            template: '<li><slot></slot></li>'
        });

        Vue.component('posts', {

            template: `
              <div>
                  <ul>
                     <post v-for="post in posts" :key="post.id">{{post.title}}</post>
                  </ul>
              </div>
            `,

            data() {
                return {
                    posts: [
                        {id: 1, title: 'Post 1'},
                        {id: 2, title: 'Post 2'},
                        {id: 3, title: 'Post 3'},
                        {id: 4, title: 'Post 4'},
                        {id: 5, title: 'Post 5'},
                    ]
                }
            },

            methods: {
                display() {
                    console.log('hello');
                }
            }
        });

        let vm = new Vue({
            el: '#app'
        });
    </script>