One place for hosting & domains

      Tutorial

      Create and Manage StackScripts – A Tutorial


      Updated by Linode

      Written by Linode

      What are StackScripts?

      StackScripts provide Linode users with the ability to automate the deployment of custom systems on top of Linode’s default Linux distribution images. For example, every time you deploy a new Linode you might execute the same tasks, like updating your system’s software, installing your favorite Linux tools, and adding a limited user account. These tasks can be automated using a StackScript that will perform these actions for you as part of your Linode’s first boot process.

      All StackScripts are stored in the Linode Cloud Manager and can be accessed whenever you deploy a Linode. A StackScript authored by you is an Account StackScript. While a Community StackScript is a StackScript created by a Linode community member that has made their StackScript publicly available in the Linode Cloud Manager.

      In this Guide

      This guide will show you how to do the following:

      Note

      Create a New StackScript

      1. Log into the Linode Cloud Manager.

      2. Click on the StackScripts link in the left-hand navigation menu. You will be brought to the StackScripts page.

        Click on the StackScripts link in the left-hand navigation menu.

      3. Viewing the Account StackScripts section, click on the Create New StackScript link at the top of the page.

        Click on the Create New StackScript link.

      4. On the Create New StackScript page, provide the required configurations to create your StackScript.

        Field Description
        StackScript Label The name with which to identify your StackScript. Required.
        Description An overview of what your StackScript does.
        Target Images The Linux distributions that can run this StackScript. Required.
        Script The body of the script. See the Writing Scripts for Use with Linode StackScripts section for more details. Required.
        Revision Note A short description of the updates made to your StackScript in this version of your script.



        Example Script

        The file below displays an example of a simple script that executes some basic set up steps on a Linode. Review the example’s comments for details on what each line of the script does.

        Example Script
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        
        #!/bin/bash
        # This block defines the variables the user of the script needs to provide
        # when deploying using this script.
        #
        #
        #<UDF name="hostname" label="The hostname for the new Linode.">
        # HOSTNAME=
        #
        #<UDF name="fqdn" label="The new Linode's Fully Qualified Domain Name">
        # FQDN=
        
        # This sets the variable $IPADDR to the IP address the new Linode receives.
        IPADDR=$(/sbin/ifconfig eth0 | awk '/inet / { print $2 }' | sed 's/addr://')
        
        # This updates the packages on the system from the distribution repositories.
        apt-get update
        apt-get upgrade -y
        
        # This section sets the hostname.
        echo $HOSTNAME > /etc/hostname
        hostname -F /etc/hostname
        
        # This section sets the Fully Qualified Domain Name (FQDN) in the hosts file.
        echo $IPADDR $FQDN $HOSTNAME >> /etc/hosts
      5. Click Save when you are done. You can always edit your script later if needed. You will be brought back to the StackScripts page, where your new StackScript will be visible and ready to use with a new Linode deployment.

        Note

        View your new StackScript on the StackScripts page.

      Manage StackScripts

      Edit an Account StackScript

      After you’ve created an Account StackScript, you can go back and edit it as required. This section will show you how to access a StackScript for editing.

      1. Log into the Linode Cloud Manager.

      2. Click on the StackScripts link in the left-hand navigation menu. You will be brought to the StackScripts page.

        Click on the StackScripts link in the left-hand navigation menu.

      3. Viewing the Account StackScripts tab, you will see a list of all of your account’s StackScripts. This will include both private and public StackScripts. Click on the more options ellipsis corresponding to the StackScript you’d like to modify and select Edit from the dropdown menu.

        Select **Edit** from the dropdown menu to edit your StackScript.

      4. On your StackScript’s Edit page, modify it as needed and click Save to keep your changes.

      Make an Account StackScript Public

      You can make any of your Account StackScripts public. When an account StackScript is public it will become available to the rest of the Linode Community in the Cloud Manager as a Community StackScript.

      Caution

      Once you make an Account StackScript public, you will not be able to make it private again or to delete it. You can, however, edit your public StackScript, if needed.

      1. Log into the Linode Cloud Manager.

      2. Click on the StackScripts link in the left-hand navigation menu. You will be brought to the StackScripts page.

        Click on the StackScripts link in the left-hand navigation menu.

      3. Viewing the Account StackScripts tab, you will see a list of all of your account’s StackScripts. This will include both private and public StackScripts. Click on the more options ellipsis corresponding to the StackScript you’d like to make public and select Make StackScript Public from the dropdown menu.

        Select Make StackScript Public from the dropdown menu.

        A dialog box will appear asking you to confirm the action. Click on Yes, make me a star! if you would like to proceed. You will be brought back to the Account StackScripts page.

        Note

      Delete an Account StackScript

      Note

      You cannot delete Account StackScripts that have been made public.
      1. Click on the StackScripts link in the left-hand navigation menu. You will be brought to the StackScripts page.

        Click on the StackScripts link in the left-hand navigation menu.

      2. Viewing the Account StackScripts tab, you will see a list of all of your account’s StackScripts. Click on the more options ellipsis corresponding to the StackScript you’d like to delete and select Delete from the dropdown menu.

        Select Make StackScript Public from the dropdown menu.

        A dialog box will appear asking you to confirm the action. Click on Delete if you would like to proceed.

      Next Steps

      Now that you have created a StackScript, you can deploy a Linode using your StackScript. See the Deploying a New Linode Using a StackScript guide for details.

      This guide is published under a CC BY-ND 4.0 license.



      Source link

      Writing Scripts for Use with Linode StackScripts – A Tutorial


      Updated by Linode

      Contributed by
      Linode

      What are StackScripts?

      StackScripts provide Linode users with the ability to automate the deployment of custom systems on top of Linode’s default Linux distribution images. For example, every time you deploy a new Linode you might execute the same tasks, like updating your system’s software, installing your favorite Linux tools, and adding a limited user account. These tasks can be automated using a StackScript that will perform these actions for you as part of your Linode’s first boot process.

      All StackScripts are stored in the Linode Cloud Manager and can be accessed whenever you deploy a Linode. A StackScript authored by you is an Account StackScript. While a Community StackScript is a StackScript created by a Linode community member that has made their StackScript publicly available in the Linode Cloud Manager.

      In this Guide

      Writing a script for use in a StackScript will generally be the same as writing a script that will be executed from the command line or another program. This guide includes information about the StackScript system, including the following:

      The StackScript System

      StackScript Requirements

      • The primary requirement for your scripts is that the interpreter needed to execute your script should exist in the Linode base image you are deploying. While Bash is an obvious choice for a script, you may choose any scripting language.

        Note

        Linode images are created using “vanilla” versions of its given distribution. Consult our Choosing a Linux Distribution guide to see list of all distributions Linode provides and to access each distribution’s corresponding websites. You can find more information on the interpreters available for each distribution on their official websites.
      • When writing a script, you must use a shebang as the first line of your script. This indicates to your Linux system which interpreter to use when running the script. For example, if you are writing a Bash script, the beginning of your script should include the following line:

        Or, if you are writing a Python script, the beginning of your script should include the following line:

        1
        2
        
        #!/usr/bin/env python
              

      Import a StackScript

      Your scripts can import any Account StackScript that you own or any Community StackScript. This allows you to reuse code minimizing what you need to write in your own scripts.

      • The example below shows the syntax to import another StackScript. As a result of including this line in a script, the imported StackScript will be downloaded as ssinclude-[NUMBER] to your Linode. However, it must be run in order to execute its contents.

        1
        2
        
        <ssinclude StackScriptID="[NUMBER]">
            

        In Bash, you can download and run the script in the following way:

        1
        2
        
        source <ssinclude StackScriptID="[NUMBER]">
            

        If you’re scripting in another language, import the StackScript, then execute it on a second line:

        1
        2
        3
        
        <ssinclude StackScriptID="[NUMBER]">
        ./ssinclude-[NUMBER]
            
      • Linode provides a StackScript Bash Library that includes a set of functions that perform various common tasks users might wish to execute on their Linodes. This script creates the functions, but does not run them. A new StackScript can import the Bash Library and then execute functions from it.

        Note

      Access a StackScript’s ID Number

      Follow the steps in this section to find the ID number of a StackScript.

      1. Log into the Linode Cloud Manager.

      2. Click on the StackScripts link in the left-hand navigation menu. You will be brought to the StackScripts page.

        Click on the StackScripts link in the left-hand navigation menu.

      3. Click on the Account StackScripts tab or the Community StackScripts tab, depending on the type of StackScript whose ID you’d like to find

      4. Click on the StackScript whose ID you’d like to access. This will bring you to its StackScript detail page.

        View the details and contents of an Account StackScript.

      5. The StackScript detail page’s URL will display the StackScript’s ID number. You can now use this number to import the StackScript into your own script.

        Access a StackScript's ID number.

      User Defined Fields (UDFs)

      The StackScript system provides a basic markup specification that interfaces with the Linode deployment process so that users can customize the behavior of a StackScript on a per-deployment basis. When a StackScript contains a user defined field (UDF), the Linode Cloud Manager will present the UDF as a form field, so a user can insert a corresponding custom value. The values and their related variables are inserted into the script’s environment when used to deploy a new Linode.

      Default Environment Variables

      Linode StackScripts provide a set of default environment variables that you can use to provide your script with information about the Linode it has deployed.

      Environment Variable Description
      LINODE_ID The deployed Linode’s ID number
      LINODE_LISHUSERNAME The deployed Linode’s full Linode Shell (LISH) accessible name.
      LINODE_RAM The RAM available on this Linode’s plan.
      LINODE_DATACENTERID The ID number of the data center containing the Linode. You can use the Linode API to see a list of all data center IDs.



      Set your Environment Variables Using an External File

      It is possible to set your script’s environment variables using externally hosted files. The example Bash script uses the wget utility to download two files named base.env and $IPADDR.env from the external site http://example.com/. The source command will load the downloaded files into the script.

      StackScript
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      # [...]
      IPADDR=$(/sbin/ifconfig eth0 | awk '/inet / { print $2 }' | sed 's/addr://')
      
      wget http://example.com/base.env --output-document=/tmp/base.env
      wget http://example.com/$IPADDR.env --output-document=/tmp/system.env
      
      source /tmp/base.env
      source /tmp/system.env
      # [...]

      Note

      The files you reference within your script must exist and be accessible via HTTP. Also, ensure that the files you host externally do not contain any sensitive information.

      StackScript Examples

      Using an External Script

      • If you have an existing deployment script, you can use a StackScript to deploy Linode instances with it. The following example StackScript installs PHP on the Linode, downloads an external PHP script from the URL http://example.com/deployment-script.php, makes it executable, and then runs the downloaded script.

        StackScript
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        
        #!/bin/bash
        if [ -f /etc/apt/sources.list ]; then
           apt-get upgrade
           apt-get -y install php
        elif [-f /etc/yum.conf ]; then
           yum -y install php
        elif [-f /etc/pacman.conf ]; then
           pacman -Sy
           pacman -S --noconfirm pacman
           pacman -S --noconfirm php
        else
           echo "Your distribution is not supported by this StackScript"
           exit
        fi
        
        wget http://example.com/deployment-script.php --output-document=/opt/deployment-script.php
        chmod +x /opt/deployment-script.php
        
        ./opt/deployment-script.php
            
      • If you do not want to rely on an existing external server to host your scripts for download, you can embed the bootstrapped script into the StackScript.

        StackScript
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        
        #!/bin/bash
        
        if [ -f /etc/apt/sources.list ]; then
           apt-get upgrade
           apt-get -y install php5
        elif [-f /etc/yum.conf ]; then
           yum -y install php
        elif [-f /etc/pacman.conf ]; then
           pacman -Sy
           pacman -S --noconfirm pacman
           pacman -S --noconfirm php
        else
           echo "Your distribution is not supported by this StackScript"
           exit
        fi
        
        cat >/opt/deployment-script.php <<EOF
        #!/usr/bin/php
        <?php print('Hello World!'); ?>
        EOF
        
        chmod +x /opt/deployment-script.php
        
        ./opt/deployment-script.php
        
            

      Next Steps

      This guide is published under a CC BY-ND 4.0 license.



      Source link

      Building and Using VueJS Components – A Tutorial


      Updated by Linode Contributed by Pavel Petrov

      How to Build and Use VueJS Components

      What are VueJS Components

      In VueJS, components are a way to create custom VueJS instances which can easily be reused in your code. In order to properly explain what VueJS components are we will build a very simple rating-counter component.

      This guide is written for new VueJS users and will explain what are components are, how to build them, and how to use them. Basic knowledge of JavaScript and VueJS is important for following through with the tutorial.

      In this guide you learn how to:

      Note

      Prepare the Vue App

      In your text editor on your computer, create a new file called ratingcounter.html. Then, paste in the content from this snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
      </div>
      
      <script>
      var app = new Vue({
        el: '#app'
      })
      </script>

      As this will be a simple VueJS application, the first thing we have to do is include the VueJS library in our document.

      • The easiest way that is done is by going to the Installation page at vuejs.org and copying the script tag specified under CDN.

      • As we are in the development stage of the application, we will use the development version of the VueJS library. This line is copied into line 1 of the HTML snippet.

      After the VueJS library is included, a div with id set to app is created on lines 3-4. On lines 6-10, a barebones VueJS app is created and linked to this element.

      So far this new app does nothing at all, but we will use it for the skeleton of our example application.

      Creating your First Component

      The component we’ll be developing is a simple reusable rating counter that will illustrate how VueJS components work. We’ll explain each part of the component along the way. Let’s get started:

      Define the Component

      In your ratingcounter.html, update the second <script> section (currently on lines 6-10 of your file) to include the Vue.component() function from lines 7-18 of this snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
      </div>
      
      <script>
      Vue.component('rating-counter', {
          data() {
              return {
                  count: 0
              }
          },
          template:   `<div>
                          <button v-on:click="count--">Thumbs Down</button>
                          {{ count }}
                          <button v-on:click="count++">Thumbs Up</button>
                      </div>`
      })
      
      var app = new Vue({
        el: '#app'
      })
      </script>

      Let’s go through each part of the component:

      • The first parameter of the Vue.component() function is the component’s name, in this case rating-counter (line 7). You will be referring to this component by its name in order to render it (described in the next section: Use the Component).

      • The second argument to the Vue.component() function is the component’s options (lines 8-18). We only use two options: the data function and the template.

      • The component’s data must be a function. This is because each instance of the component must have a separate and independent copy of the data object. Otherwise, each time we reuse a component it would inherit the data from the other instances of the component.

      • The template contains the HTML this component will render:

        • VueJS uses mustache tags to render strings. In our example, {{ count }} (line 19) will render the count from the component’s data.

          What is interesting is that as VueJS is reactive, when you change your variable the view automatically updates it, and you don’t have to add any code to make this work.

        • Another thing you probably noticed in the template is the v-on:click attribute of the buttons (lines 14 and 16). Similar to jQuery’s .on(‘click’, func), you can use this feature to attach a function to the on-click event of the element.

          This can either be pointed to a function, or you can use JavaScript operators. This example uses the increment ++ and decrement -- operators directly in the attribute itself.

      At this point, we’ve built our first component, but it won’t be visible yet if you load ratingcounter.html in your browser.

      Use the Component

      Let’s try the new component out. In your ratingcounter.html, update the app div as follows:

      ratingcounter.html
      1
      2
      3
      4
      5
      
      <div id="app">
         <rating-counter></rating-counter>
         <rating-counter></rating-counter>
         <rating-counter></rating-counter>
      </div>

      This will render three rating counters which work independently from one another:

      First component

      Awesome. Let’s say however that we need to pass arguments from the parent application to the component. The option for that is called props.

      Using Component Props

      Props are VueJS’s method for adding custom properties to your component. To demonstrate this concept, let’s modify our component a little bit:

      1. In ratingcounter.html, update your Vue.component() declaration as follows:

        ratingcounter
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        
        Vue.component('rating-counter', {
            props: ['title'],
            data() {
                return {
                    count: 0
                }
            },
            template:   `<div>
                            <h1>{{ title }}</h1>
                            <button v-on:click="count--">Thumbs Down</button>
                            {{ count }}
                            <button v-on:click="count++">Thumbs Up</button>
                        </div>`
        })

        The props option has been added on line 2 of this snippet, and you can access its values from the template with the mustache syntax, just like a regular data parameter. In line 9 of this snippet, the reference to {{ title }} has been added to the template.

      2. How can you actually pass data to a prop? Just pass title as an attribute to your component’s opening tag. Whatever you pass there would be accessible by your component.

        In your ratingcounter.html, update the app div as follows:

        ratingcounter.html
        1
        2
        3
        4
        5
        
        <div id="app">
           <rating-counter title="Rating 1"></rating-counter>
           <rating-counter title="Rating 2"></rating-counter>
           <rating-counter title="Rating 3"></rating-counter>
        </div>
      3. If you reload the file in your browser, you’ll now see a title rendered for each component instance. Voila:

        Component props

      Sharing Data Between Components and the Parent App

      Just as a Vue component can keep track of data used in that component, the Vue app itself can also maintain its own data object. This section will show how props can also be used to share that data with your components.

      Replace the contents of your ratingcounter.html with the following snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
         {{ parentHeader.label }}{{ parentHeader.globalCount }}
         <hr />
         <rating-counter title="Rating 1" v-bind:parent="parentHeader"></rating-counter>
         <rating-counter title="Rating 2" v-bind:parent="parentHeader"></rating-counter>
         <rating-counter title="Rating 3" v-bind:parent="parentHeader"></rating-counter>
      </div>
      
      <script>
      Vue.component('rating-counter', {
          props: ['title', 'parent'],
          data() {
              return {
                  count: 0
              }
          },
          template:   `<div>
                          <h1>{{ title }}</h1>
                          <button v-on:click="count--;parent.globalCount--;">Thumbs Down</button>
                          {{ count }}
                          <button v-on:click="count++;parent.globalCount++;">Thumbs Up</button>
                      </div>`
      })
      
      new Vue({
          el: '#app',
          data: {
              parentHeader: {
                  label: "Counter is at: ",
                  globalCount: 0
              }
          }
      })
      </script>

      Load the file in your browser and start clicking the buttons. You’ll now see a label at the top of the page that counts up the total from each of your components:

      Component with bound data properties

      Let’s break down the updated parts of the file:

      • The parent app’s data is set on lines 29-34. The app now keeps track of an object called parentHeader.

      • The data from this object is rendered on line 4.

      • On line 13, we’ve added another prop to the component, called parent.

      • On lines 6-8, the value for this prop is assigned with the v-bind:parent attribute. By using the v-bind syntax, you’re telling VueJS to bind the parent attribute of the component to whichever data property you supply, in this case the parentHeader object.

      • On lines 21 and 23, the on-click actions for each button will increment or decrement the globalCount property of the parent prop, which corresponds to the globalCount property of the parentHeader object in your app’s data.

      • Because props are reactive, changing this data from the component will cascade the changes back to the parent, and to all other components that reference it.

      Using Slots

      Slots are another very clever way to pass data from parent to components in VueJS. Instead of using attributes as you did before, you can pass data within the component’s opening and closing HTML tags. Let’s take a look at the below example:

      Replace the contents of your ratingcounter.html with the following snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
         {{ parentHeader.label }}{{ parentHeader.globalCount }}
         <hr />
         <rating-counter v-bind:parent="parentHeader"><h1>Rating 1</h1></rating-counter>
         <rating-counter v-bind:parent="parentHeader"><h1>Rating 2</h1></rating-counter>
         <rating-counter v-bind:parent="parentHeader"><h1>Rating 3</h1></rating-counter>
      </div>
      
      <script>
      Vue.component('rating-counter', {
          props: ['parent'],
          data() {
              return {
                  count: 0
              }
          },
          template:   `<div>
                          <slot></slot>
                          <button v-on:click="count--;parent.globalCount--;">Thumbs Down</button>
                          {{ count }}
                          <button v-on:click="count++;parent.globalCount++;">Thumbs Up</button>
                      </div>`
      })
      
      new Vue({
          el: '#app',
          data: {
              parentHeader: {
                  label: "Counter is at: ",
                  globalCount: 0
              }
          }
      })
      </script>

      When loaded in a browser, the page should appear identical to the example in the previous section.

      On lines 6-8, notice how instead of passing the title prop with an argument, we pass it within the component’s open and close tags:

      <rating-counter v-bind:parent="parentHeader"><h1>Rating 1</h1></rating-counter>

      On line 20, the slot is referenced with the <slot></slot> syntax. As shown in this example, slots support HTML. As well, they have access to the parent’s scope (not demonstrated here), and they even support nesting more components.

      About slot scope

      Slot scope is an important concept to grasp when working with slots. Even though the content you are passing from the parent is intended for the component, you are still within the context of the parent.

      For example, trying to access the count data of the rating-counter component like this would fail:

      <rating-counter v-bind:parent="parentHeader">
          <h1>{{ count }}</h1>
      </rating-counter>

      However, as you are within the scope of the parent app, you can access the parentHeader object (or any other app data):

      <rating-counter v-bind:parent="parentHeader">
          <h1>{{ parentHeader.label }}</h1>
      </rating-counter>

      Using the parentHeader.label string here wouldn’t make much sense anyway, so this would only serve to demonstrate the scope concept.

      Nesting Slots

      The most important feature of slots might be the ability to use components within components. This is especially useful when creating structure for your apps.

      Replace the contents of your ratingcounter.html with the following snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
          {{ parentHeader.label }}{{ parentHeader.globalCount }}
          <hr />
      
          <rating-counter v-bind:parent="parentHeader">
              <rating-title>Rating 1</rating-title>
          </rating-counter>
      
          <rating-counter v-bind:parent="parentHeader">
              <rating-title>Rating 2</rating-title>
          </rating-counter>
      
          <rating-counter v-bind:parent="parentHeader">
              <rating-title></rating-title>
          </rating-counter>
      </div>
      
      <script>
      Vue.component('rating-counter', {
          props: ['parent'],
          data() {
              return {
                  count: 0
              }
          },
          template:   `<div>
                          <slot></slot>
                          <button v-on:click="count--;parent.globalCount--;">Thumbs Down</button>
                          {{ count }}
                          <button v-on:click="count++;parent.globalCount++;">Thumbs Up</button>
                      </div>`
      })
      
      Vue.component('rating-title', {
          template:   `<div>
                          <h1>
                              <slot>Default Rating Title</slot>
                          </h1>
                      </div>`
      })
      
      new Vue({
          el: '#app',
          data: {
              parentHeader: {
                  label: "Counter is at: ",
                  globalCount: 0
              }
          }
      })
      </script>

      We’ve created another component called rating-title to illustrate slot nesting. This component will wrap a title that you set inside a pair of <h1> tags:

      Components with nested slots

      Let’s explore the code for this component:

      • The template for the new component is defined on lines 37-41. The <slot> tag has been added to this template, but this time the slot is not empty.

      • You can specify the default value for slots by adding it between the open and close slot tags: <slot>Default Rating Title</slot>

      • You can see how this default value is referenced for the new rating-title component on line 16. Whenever nothing is included between the <rating-title></rating-title> tags, the default value is used.

      • Compare this with how the component is used on lines 8 and 12. Because a title is included between the component’s tags, the default text is is not rendered.

      Named Slots

      To allow even more structure, you can use multiple slots in a template by using slot naming. Lets overengineer our simple example a little bit to see how it works.

      Replace the contents of your ratingcounter.html with the following snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
          {{ parentHeader.label }}{{ parentHeader.globalCount }}
          <hr />
      
         <rating-counter v-bind:parent="parentHeader">
             <template v-slot:title>
                 <rating-title></rating-title>
             </template>
             <template v-slot:subtitle>
                 Subtitle
             </template>
         </rating-counter>
      </div>
      
      <script>
      Vue.component('rating-counter', {
          props: ['parent'],
          data() {
              return {
                  count: 0
              }
          },
          template:   `<div>
                          <slot name="title"></slot>
                          <h2>
                              <slot name="subtitle"></slot>
                          </h2>
                          <button v-on:click="count--;parent.globalCount--;">Thumbs Down</button>
                          {{ count }}
                          <button v-on:click="count++;parent.globalCount++;">Thumbs Up</button>
                      </div>`
      })
      
      Vue.component('rating-title', {
          template:   `<div>
                          <h1>
                              <slot>Default Rating Title</slot>
                          </h1>
                      </div>`
      })
      
      new Vue({
          el: '#app',
          data: {
              parentHeader: {
                  label: "Counter is at: ",
                  globalCount: 0
              }
          }
      })
      </script>

      When loaded in a browser, the file will look like:

      Components with named slots

      • You can see that within our rating-counter component (on lines 26-29) there are now two slots. This time they have name attributes as well: title and subtitle.

      • This takes care of the creation of the named slots, but how do we use them? You can reference a named slot by using the <template v-slot:slotname></template> syntax within your parent component. The content inside the <template> tags will then be inserted where the <slot> with the same name appears in your component’s template.

      Using Component Events

      Events in components are essential for component-to-parent communication in VueJS. Whenever a component needs to communicate back to its parent, this is the safe way of doing that.

      For an example of how this works, replace the contents of your ratingcounter.html with the following snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
          {{ parentHeader.label+" "+parentHeader.globalCount }}
          <hr />
      
          <rating-counter v-bind:parent="parentHeader" v-on:increment="parentHeader.globalCount++"></rating-counter>
      </div>
      
      <script>
      Vue.component('rating-counter', {
          template:   `<div>
                          <br><button v-on:click="$emit('increment');">Thumbs Up</button>
                      </div>`
      })
      
      new Vue({
          el: '#app',
          data: {
              parentHeader: {
                  label: "Counter is at: ",
                  globalCount: 0
              }
          }
      })
      </script>

      When loaded in a browser, the file will look like:

      Component with an event

      The example is similar to the previous examples, but we’ve only left what is essential to the events:

      • In the v-on:click event of our component (line 13), you can see that this time we’re using VueJS’s $emit method instead of changing variables manually. The $emit() method takes a custom event name as an argument (increment in this example).

      • This fires an empty increment event, which our parent is subscribed to on line 7. Notice the v-on:increment="parentHeader.globalCount++" attribute; this is our event subscriber.

      • The subscriber can call a method of the VueJS app, or in this example, just directly use the increment JavaScript ++ operator to increase the counter.

      • Because the component no longer directly manipulates the parent’s globalCount data, the parent prop for the component can be removed.

      Passing a Parameter with Events

      How about if you want to pass a parameter with the event? We’ve got you covered.

      For an example of how this works, replace the contents of your ratingcounter.html with the following snippet:

      ratingcounter.html
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      
      <div id="app">
          {{ parentHeader.label+" "+parentHeader.globalCount }}
          <hr />
      
          <rating-counter v-bind:parent="parentHeader" v-on:increment="parentHeader.globalCount+=$event"></rating-counter>
      </div>
      
      <script>
      Vue.component('rating-counter', {
          template:   `<div>
                          <button v-on:click="$emit('increment', -1);">Thumbs Down</button>
                          <button v-on:click="$emit('increment', 1);">Thumbs Up</button>
                      </div>`,
      
      })
      
      new Vue({
          el: '#app',
          data: {
              parentHeader: {
                  label: "Counter is at: ",
                  globalCount: 0
              }
          }
      })
      </script>

      When loaded in a browser, the file will look like:

      Component with an event and parameter

      • This example introduces a second parameter of the $emit() function (lines 13-14).

      • Instead of simply incrementing by one, our parent event subscriber can make use of this argument with the $event variable (line 7).

      • The template for the component now has a Thumbs Down button again, and the argument for this button’s event is -1 (line 13).

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      This guide is published under a CC BY-ND 4.0 license.



      Source link