Categories
JavaScript Nodejs

How To Build a Reverse Proxy With Express

If you use microservices architecture for your distributed system, there is a need for an API gateway. One good way to build an API gateway is to use a reverse proxy. Node.js is good for a reverse proxy because it’s fast and has lots of libraries to make a reverse proxy.

Express is the most popular framework for building web apps. It’s also very good for building a reverse proxy because there are add-ons to Express that can do the routing for the reverse proxy.

The design will be very simple. It will only redirect traffic to our different back-end apps according to the URL of the request. Also, it has to be able to pass header data, files, and cookies into our services in addition to the request payload.

To do all this, we first scaffold our app by running the Express application generator by following the instructions at https://expressjs.com/en/starter/generator.html

We have to run npx express-generator to generate the code that we need.

I suggest using nodemon to run our app in a development environment so that it restarts whenever our code changes.

Next, we have to install some packages to do the reverse proxy function and to enable CORS so that front end apps can use the reverse proxy. To do this, run npm i express-http-proxy glob node-env-file cookie-parser babel-register body-parser .

express-http-proxy is the HTTP reverse proxy library. cors is an add-on for Express that enables CORS. cookie-parser is an add-on allows Express to parse cookies. babel-register allows us to use the latest JavaScript features. node-env-file allows us to use .env file for storing environment variables. body-parser will be used to check for multipart requests. Multipart requests are requests that have files. The requests with files will not go through body-parser before redirecting.

Now we are ready to write code. We make a new file called helper.js in the helpers folder that we create.

In there, we add:

module.exports = {  
    isMultipartRequest: (req) => {  
        let contentTypeHeader = req.headers['content-type'];  
        return contentTypeHeader && contentTypeHeader.indexOf('multipart') > -1;  
    }  
}

This function checks for multipart requests, which are requests that are sent in as form data. It can include text or files.

In app.js , we write:

require("babel-register");  
let express = require('express');  
let cors = require('cors')  
let config = require('./config/config');  
let env = require('node-env-file');  
let helpers = require('./app/helpers/helpers');  
let bodyParser = require('body-parser');  
env(__dirname + '/.env');
let app = express();

app.use(cors({  
  credentials: true,  
  origin: true  
}));

const bodyParserJsonMiddleware = function () {  
  return function (req, res, next) {  
    if (helpers.isMultipartRequest(req)) {  
      return next();  
    }  
    return bodyParser.json()(req, res, next);  
  };  
};

app.use(bodyParserJsonMiddleware());

app.all('*', (req, res, next) => {  
  let origin = req.get('origin');  
  res.header('Access-Control-Allow-Origin', origin);  
  res.header("Access-Control-Allow-Headers", "X-Requested-With");  
  res.header('Access-Control-Allow-Headers', 'Content-Type');  
  next();  
});

module.exports = require('./config/express')(app, config);

app.listen(config.port, () => {  
  console.log('Express server listening on port ' + config.port);  
});

The code works by passing on server-side cookies and allows multipart requests to not pass through body-parser since it is not JSON.

Also, we allow CORS in the block below:

app.all('*', (req, res, next) => {  
  let origin = req.get('origin');  
  res.header('Access-Control-Allow-Origin', origin);  
  res.header("Access-Control-Allow-Headers", "X-Requested-With");  
  res.header('Access-Control-Allow-Headers', 'Content-Type');  
  next();  
});

It allows requests from all origins to be accepted. By default, only requests from the same host as the back end are accepted since it is insecure to allow requests from other hosts. However, if we allow mobile and standalone front-end web apps to make requests through our reverse proxy, we have to allow all origins. It gets the origin from the header and allows the request from that origin to proceed.

Then we add the code for proxying requests in controllers/home.js:

const express = require('express');  
let proxy = require("express-http-proxy");  
let helpers = require('../helpers/helpers');
let loginAppRoutes =[  
  '/login*',  
  '/loginms',  
  '/register',  
  '/resetPassword',  
  '/getActivationKey*',  
  '/activateAccount',  
  '/logout',  
  '/reports',  
  '/'  
]

let uploadRoutes = [  
  '/uploadlogo*',  
]

module.exports = (app) => {  
  const proxyMiddleware = () => {  
    return (req, res, next) => {  
      let reqAsBuffer = false;  
      let reqBodyEncoding = true;  
      let contentTypeHeader = req.headers['content-type'];  
      if (helpers.isMultipartRequest(req)) {  
        reqAsBuffer = true;  
        reqBodyEncoding = null;  
      }  
      return proxy(process.env.UPLOAD_URL, {  
        reqAsBuffer: reqAsBuffer,  
        reqBodyEncoding: reqBodyEncoding,  
        parseReqBody: false,  
        proxyReqOptDecorator: (proxyReq) => {  
          return proxyReq;  
        }, 

        proxyReqPathResolver: (req) => {  
          return `${process.env.UPLOAD_APP_URL}/${req.baseUrl}${req.url.slice(1)}`;  
        }, 

        userResDecorator: (rsp, data, req, res) => {  
          res.set('Access-Control-Allow-Origin', req.headers.origin);  
          return data.toString('utf-8');  
        }  
      })(req, res, next);  
    };  
  } 

  uploadRoutes.forEach(r => {  
    app.use(r, proxyMiddleware());  
  }) 

  loginAppRoutes.forEach(r => {  
    app.use(r, proxy(process.env.LOGIN_URL, {  
      proxyReqOptDecorator: (proxyReq) => {  
        return proxyReq;  
      },

      proxyReqPathResolver: (req) => {  
        return `${process.env.LOGIN_URL}/${req.baseUrl}${req.url.slice(1)}`;  
      }, 

      userResDecorator: (rsp, data, req, res) => {  
        res.set('Access-Control-Allow-Origin', req.headers.origin);  
        return data.toString('utf-8');  
      }  
    }));  
  })  
};

We check for multipart form requests with:

if (helpers.isMultipartRequest(req)) {  
  reqAsBuffer = true;  
  reqBodyEncoding = null;  
}

The will pass requests with files straight through to our internal APIs.

The following:

proxyReqPathResolver: (req) => {  
  return `${process.env.LOGIN_URL}/${req.baseUrl}${req.url.slice(1)}`;  
},

is where the actual redirect URL from the proxy to internal API is set. Note that parseReqBody is false , so that multipart form requests are not parsed as JSON.

The process.env variables are set in the .env file.

In the .env file, we have:

LOGIN_URL='http://urlForYourLoginApp'  
UPLOAD_URL='http://anotherUrlForYourUploadApp'

With reverse proxy add-on, Express is one of the best choices for building a reverse proxy in Node.

Categories
JavaScript Vue

Basic Vue Form Validation with VeeValidate

Form validation is a common requirement of in most web apps. This is no different with Vue apps.

Vue doesn’t provide a solution for form validation out of the box. Therefore, we have to find our own solution for form validation.

In this article, we’ll look at how to do basic Vue form validation with VeeValidate.

Getting Started

We can get started by including the VeeValidate library by writing:

<script src="https://unpkg.com/vee-validate@latest"></script>

in our HTML file.

Then we can write:

Vue.component("validation-provider", VeeValidate.ValidationProvider);

to include the validation-provider component in our app. We need to wrap this around our form fields to let VeeValidate do validation on it.

Then we need to define some form validation rules to actually do the form validation.

To do this, we use the VeeValidate.extend function, which takes the rule name string as the first argument, and the callback function that returns the condition for a validate input as the second argument.

For instance, we can use Veelidate.extend as follows to create a rule for for validating that the inputted value is an odd number:

VeeValidate.extend("odd", value => {
  return value % 2 !== 0;
});

In the code above, we check if value % 2 returns 0 or not. If it doesn’t then it’s an odd number.

Likewise, we can do something similar to check if an inputted value is a positive number as follows:

VeeValidate.extend("positive", value => {
  return value >= 0;
});

We can use the rules as follows in a small app with a form field that we can enter something into:

index.js:

Vue.component("validation-provider", VeeValidate.ValidationProvider);

VeeValidate.extend("odd", value => {
  return value % 2 !== 0;
});

VeeValidate.extend("positive", value => {
  return value >= 0;
});
new Vue({
  el: "#app",
  data: {
    value: ""
  }
});

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vee-validate@latest"></script>
  </head>
  <body>
    <div id="app">
      <validation-provider rules="positive|odd" v-slot="{ errors }">
        <input v-model="value" type="text" name="value" />
        <span>{{ errors[0] }}</span>
      </validation-provider>
    </div>
    <script src="index.js"></script>
  </body>
</html>

In the template above, we have a slot that gets the errors object from the validation-provider component which contains the form validation errors messages.

We display the first one by accessing the string on the 0 index of errors.

The rules prop has the rules separated by the | symbol. We applied the positive and odd rules that we defined earlier in index.js

Note that the validation-provider is wrapped around our input. This is required to validate the input. We wrap one validation-provider per input.

Then when type in something that’s not a positive, odd number, we’ll see ‘value is not valid’ displayed.

value is from the value of the name attribute of the input.

Rule Arguments

We can pass in arguments to rule callbacks so that we can do more complex validations. For instance, we can write the following rule to validate that the inputted value is a number bigger than or equal to a certain number:

VeeValidate.extend("min", {
  validate(value, args) {
    return value >= args.num;
  },
  params: ["num"]
});

Then we can apply it as follows:

index.js:

Vue.component("validation-provider", VeeValidate.ValidationProvider);

VeeValidate.extend("min", {
  validate(value, args) {
    return value >= args.num;
  },
  params: ["num"]
});

new Vue({
  el: "#app",
  data: {
    value: ""
  }
});

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vee-validate@latest"></script>
  </head>
  <body>
    <div id="app">
      <validation-provider rules="min:5" v-slot="{ errors }">
        <input v-model="value" type="text" name="value" />
        <span>{{ errors[0] }}</span>
      </validation-provider>
    </div>
    <script src="index.js"></script>
  </body>
</html>

In the code above, we have min:5 to indicate that we want to make sure that our inputted value is 5 or greater.

Conclusion

Validation of Vue forms with VeeValidate is simple. We can do a lot with a few lines of code.

Validation rules are defined with extend. And we use the validation-provider component to validate inputs by wrapping it around the input element.

Also, we can pass in arguments to validation rules to make them more flexible.

Categories
JavaScript Mistakes

More JavaScript Mistakes You May be Making

JavaScript is a language that’s friendlier than many other programming languages in the world. However, it’s still very easy to make mistakes when writing JavaScript code through misunderstanding or overlooking stuff that we already know. By avoiding some of the mistakes below, we can make our lives easier by preventing bugs and typos in our code that bog us down with unexpected results.

Confusing Undefined and Null

JavaScript has both undefined and null for non-values. However, there are quite a few differences between the two. undefined means that the variable may have been declared, but nothing is set to it. A variable can also be explicitly set as undefined. The type of an undefined variable, when checking the type with the typeof operator, will get us the type 'undefined'. Functions that don’t return anything returns undefined. On the other hand, null values have to be explicitly set by functions that return null or just set directly to a variable. When we check an object that has the null value set, we’ll find that the type of it is'object' if a variable has the null value.

For this reason, it’s probably easier to stick to undefined whenever we can when we’re setting variable values to non-values. It reduces confusion and we only have to check that the type of a variable is 'undefined' to see whether it’s undefined. That’s less painful than having two checks, for both null and undefined.

To write functions that return undefined, we don’t have to do anything like the following example:

const f = () => {}

To set a variable that was assigned some other value to undefined, we can write:

x = undefined;

To check if a property value is undefine, we can write:

typeof obj.prop === 'undefined'

or

obj.prop === undefined

To check if a variable is undefined, we can write the following code:

typeof x === 'undefined'

A declared variable that hasn’t been assigned anything automatically has the value undefined.

If we have to check for null, then we can write:

obj.prop === null

or

x === null

for variables. We can’t use the typeof operator for checking null because the data type of null is 'object'.

Confusing Addition and Concatenation

In JavaScript, the + operator is used for both adding two numbers and concatenating strings together. Because JavaScript is a dynamic language, the operands are all automatically converted to the same type before the operation is applied. For example, if we have:

let x = 1 + 1;

then we get two because they’re both numbers. The + operation was used for addition like we expected. However, if we have the following expression:

let x = 1 + '1';

then we get '11' because the first operand was coerced into a string before the + operation is applied. The + operation was used for concatenation instead of addition. When we use the + operator on multiple variables, this makes knowing the type even harder. For example, if we have:

let x = 1;  
let y = 2;  
let z = x + y;

as we expect, we get three because x and y are both numbers. On the other hand, if we have:

let x = 1;  
let y = '2';  
let z = x + y;

then we get '12' because y is a string, so the + operator was used for concatenation instead. To solve this issue, we should convert all the operands to numbers first before using them with the + operator. For example, we should rewrite the above example into the following:

let x = 1;  
let y = '2';  
let z = Number(x) + Number(y);

The code above will get us 3 as the value of z since we converted them both to numbers with the Number factory function first. The Number function takes in any object and returns a number if it can be parsed into a number, or NaN otherwise. An alternative way to do this is to use the new Number(...).valueOf() function, as we do in the following code:

let x = 1;  
let y = '2';  
let z = new Number(x).valueOf() + new Number(y).valueOf();

Since new Number(...) is a constructor that creates an object type, we want to use the valueOf function to convert it back to a primitive type to make sure that what we get is a number type. A shorter way to do this is to write:

let x = 1;  
let y = '2';  
let z = +x + +y;

The + sign in front of a single operand will try to convert the single operand into a number or toNaN if it can’t be converted into a number. It does the same thing as the Number function. We can also convert a variable to a particular type of number. The Number object has a parseInt function to convert a string or object into an integer and a parseFloat function to convert a string or object into a floating-point number. parseInt takes the object you want to convert to a number as the first argument. It also takes a radix as an optional second argument, which is the base of the mathematical numeral systems. If the string starts with 0x, then the radix will be set to 16. If the string starts with anything else, then the radix will be set to 10.

We can use them as in the following examples:

let x = 1;  
let y = '2';  
let z = Number.parseInt(x) + Number.parseInt(y)

Also, we can use the parseFloat function as in the following code:

let x = 1;  
let y = '2';  
let z = Number.parseFloat(x) + Number.parseFloat(y)

We will get 3 in both of the examples above.

Breaking Return Statements Into Multiple Lines

JavaScript closes a statement at the end, so one line code is considered distinct from the other. For example, if we have:

const add = (a, b) => {  
  return  
  a + b;  
}

we get undefined if we run console.log(add(1, 2)); since we ran the return statement, which ended the function execution, before a + b is run. Therefore, a + b will never be run in this function. To fix this, we either have to put the return statement all in one line or use parentheses to surround what we want to return. For example, we can write:

const add = (a, b) => {  
  return a + b;  
}

This will log 3 if we run console.log(add(1, 2)); since we are actually returning the computed result in the function. We can also write:

const add = (a, b) => {  
  return (  
    a + b  
  );  
}

This is handy for returning expressions that might be longer than one line. This will also log 3 if we run console.log(add(1, 2));. For arrow functions, we can also write:

const add = (a, b) => a + b

for single-line functions since the return statement is implicit for single-line arrow functions. We can also write:

const add = (a, b) => (a + b)

to get the same thing. This also works for single-line arrow functions.

In JavaScript, if a statement is incomplete, like the first line of:

const power = (a) => {  
  const  
    power = 10;  
  return a ** 10;  
}

inside the function then the JavaScript interpreter will run the first line together with the second line to get the full statement. So:

const  
  power = 10;

is the same as:

const power = 10;

However, for complete statements like return statements, the JavaScript interpreter will treat them as separate lines. So:

return   
  a ** 10;

is not the same as:

return a ** 10;

Even though JavaScript is a friendly language, it’s still very easy to make mistakes when writing JavaScript code. It’s easy to confuse undefined and null when we aren’t familiar with JavaScript. Because of the dynamic typing nature of JavaScript, operators like the + operator that can do multiple things can easily be converted to a type we don’t expect and produce the wrong result. Also, if statements can be complete on their own, then they shouldn’t be written in their own lines if we want both lines to be together.

Categories
JavaScript JavaScript Basics

Great New Features in ES2018

Ever since ES2015 was released, which was a great leap forward in itself, JavaScript has been improving at a fast pace. Every year since then, new features have been added to JavaScript specifications.

Features like new syntax and new methods for building in JavaScript have been added consistently. In ES2016 and 2017, The Object object had methods like Object.values and Object.entries added.

String methods like padStart and padEnd were added in ES2017. async and await, which is a shorthand syntax for chaining promises, were also added in ES2017.

The includes methods for arrays were added in ES2016. ES2018 was another release with lots of new features. With ES2018, the spread syntax is now available for object literals. Rest parameters were also added.

The for await...of loop, which is a loop syntax iterating through promises sequentially, was also added. The SharedArrayBuffer object was added for representing raw binary data that cannot become detached.

A finally function was also added to the Promise object.


Spread Operator in Objects

The spread syntax works by copying the values of the original array, and then inserting them into another array or putting them in the order they appeared in the array as the list of arguments in a function in the same order.

When the spread operator is used with objects, the key-value pairs appear in the same order they appeared in the original object.

With ES2018, the spread operator works with object literals. Then key-value pairs of an object can be inserted into another object with the spread operator.

If there are two objects with the same key that the spread operator is applied to in the same object, the one that’s inserted later will overwrite the one that’s inserted earlier.

For example, if we have the following:

let obj1 = {foo: 'bar', a: 1};  
let obj2 = {foo: 'baz', b: 1};  
let obj3 = {...obj1, ...obj2 }

Then we get {foo: “baz”, a: 1, b: 1} as the value of obj3 because obj1 is spread before obj2. They both have foo as a key in the object.

First foo: 'bar' is inserted by the spread operator to obj3. Then foo: 'baz' overwrites the value of foo after obj2 is merged in since it has the same key, foo, but was inserted later.

This is great for merging objects as we don’t have to loop through the keys and put in the values, which is much more than one line of code.

One thing to note is that we can’t mix the spread operator between regular objects and iterable objects. For example, we will get TypeError if we write the following:

let obj = {foo: 'bar'};  
let array = [...obj];

Rest Operator

The rest operator is a JavaScript operator where we can store an indefinite number of arguments in a function as an array. It looks exactly like the spread operator, which lets us spread entries of an array or a list of key-value pairs of an object into another object.

For example, if we have a function that has a long list of arguments, we can use the rest operator to shorten the list of parameters in a function.

The rest operator is used with the following syntax:

const fn = (a,b,..restOfTheArgs) => {...}

Where restOfTheArgs is an array with the list of arguments other than the first two.

For example, if we want to write a sum function that takes an indefinite list of numbers as arguments and sum up the numbers, we can write:

const sum = (a,b,...otherNums) => {  
  return a + b + otherNums.reduce((x,y)=>x+y, 0);  
}

As we can see, this is very handy for functions that have any list of arguments. Before we had this, we had to use the arguments object available in functions to get a list of arguments. This is not ideal as we allow them to pass in anything into the arguments.

With the rest operator, we have the best of both worlds. We can have some fixed parameters, while the rest stay flexible. This makes functions more flexible than functions with a fixed number of parameters, while having some flexibility of functions that take an indefinite number of arguments.

The arguments object has all the arguments of the function. Also, it’s not a real array, so array functions aren’t available to them. It’s just an object with indexes and keys to denote the argument’s positions.

Methods like sort, map, forEach, or pop cannot be run on the argument’s object. It also has other properties. This creates confusion for programmers. The arguments that are converted to an array with the rest operator do not have these issues, as they are real arrays.

To call the sum function we wrote, we can write:

const result = sum(1,2,3,4,5,6,7,8,9,10);

The result will be 55, since we summed up all the arguments together. otherNums is an array with all the numbers other than 1 and 2.

We can also use the rest operator to destructure a list of arguments into a list of variables. This means that we can convert a list of parameters into an array with the spread operator, and then decompose the array of arguments into a list of variables.

This is very useful as we can get the entries of the array that’s operated on by the rest operator and convert them to named variables. For example, we can write:

const sum = (a,b,...[c,d,e])=> a+b+c+d+e;

This way, we can use the rest operator, but limit the number of arguments that your function accepts. We take the function parameters a and b, and we also take c, d, and e as parameters.

However, it’s probably clearer without using the rest operator since all the parameters are fixed, we can just list the parameters directly.


for await...of

The for await...of loop allows us to create a loop that iterates over a list of promises as well as over the entries of a normal iterables.

It works with iterable objects like arrays, string, argument object, NodeList object, TypedArray, Map, Set, and user-defined synchronous and asynchronous iterable objects.

To use it, we write:

for await (let variable of iterable) {  
  // run code on variable
}

The variable may be declared with const, let, or var, and the iterable is the iterable objects that we are iterating over. We can iterate over asynchronous iterable objects like the following:

const asynNums = {  
  [Symbol.asyncIterator]() {  
    return {  
      i: 6,  
      next() {  
        if (this.i < 20) {  
          return Promise.resolve({  
            value: this.i++,  
            done: false  
          });  
        }
        return Promise.resolve({  
          done: true  
        });  
      }  
    };  
  }  
};

(async () => {  
  for await (let num of asynNums) {  
    console.log(num);  
  }  
})();

We should see 6 to 19 logged. It also works with async generators:

async function* asynNumGenerator() {  
  var i = 6;  
  while (i < 20) {  
    yield i++;  
  }  
}

(async () => {  
  for await (let num of asynNumGenerator()) {  
    console.log(num);  
  }  
})();

We should see the same thing logged. It also works great with promises:

const arr = Array.from({  
  length: 20  
}, (v, i) => i)let promises = [];

for (let num of arr) {  
  const promise = new Promise((resolve, reject) => {  
    setTimeout(() => {  
      resolve(num);  
    }, 100)  
  })  
  promises.push(promise);  
}

(async () => {  
  for await (let num of promises) {  
    console.log(num);  
  }  
})();

As we can see, if we run the code above, we should see 0 to 19 logged sequentially, which means that promises were iterated through in sequence. This is very handy as we never have anything that can iterate through asynchronous code before this loop syntax was introduced.


Promise.finally()

The finally function is added to the Promise object which runs when the promise is settled. That means it runs whenever the promise is fulfilled or rejected.

It takes a callback function that runs whenever the promise is settled. This lets us run code regardless of how a promise ends. Also, this means that we no longer have to duplicate code in the callbacks for then and catch functions.

To use the finally function, we use it as the following:

promise  
.finally(()=>{  
  // run code that when promise is settled  
})

The finally is useful is we want to run code whenever a promise ends like cleanup code or processing after the code ends.

It’s very similar to calling .then(onFinally, onFinally). However, we do not have to declare it twice to make a variable for it and pass it in twice. The callback for the finally function doesn’t take any argument, as there’s no way to determine the status of the promise beforehand.

It’s used for cases when we don’t know what will happen to the promise, so there’s no need to provide any argument. If a promise is fulfilled then the resolved value will be intact after calling the finally function.

For example, if we have:

Promise.resolve(3).then(() => {}, () => {})

This will resolve to undefined, but if we have:

Promise.resolve(3).finally(() => {})

The code above will resolve to 3. Similarly, if the promise if rejected, we get:

Promise.reject(5).finally(() => {})

This will be rejected with the value 5.


SharedArrayBuffer

The SharedArrayBuffer is an object that’s used to represent a fixed-length raw binary data buffer.

It’s similar to the ArrayBuffer object, but we can use it to create views on shared memory. It can’t become detached, unlike an ArrayBuffer. The constructor of it takes the length of the buffer as an argument.

The length is the size in byte for the array buffer to create. It returns a SharedArrayBuffer of the specified size with contents initialized to 0.

Shared memory can be created and updated by multiple workers on the main thread. However, this may take a while until the changes are propagated to all contexts.


Conclusion

With ES2018, we have more handy features to help developers develop JavaScript apps.

The highlights include the spread operator for objects, which let us copy key-value pairs to other objects and the rest operator to let us pass optional arguments.

The for await...of loop lets us iterate through collections of asynchronous code which could never easily be done before.

Categories
JavaScript Vue

Emitting Custom Events with Vue.js

We can emit events with Vue. Events are emitted by child components and are listened to by their parent components.

Emitted can have data that’s sent along with the event emission.

In this article, we’ll look at how to emit custom Vue events with $emit and listen to them in the parent component.

We can emit events in our child component and use the listen to the event and use the emitted data as follows:

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <Foo @foo="bar = $event"></Foo>
      <p>{{bar}}</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js

Vue.component("Foo", {
  methods: {
    emit() {
      this.$emit("foo", "bar");
    }
  },
  template: `<button @click='emit'>Emit</button>`
});

new Vue({
  el: "#app",
  data: {
    bar: ""
  }
});

In the code above, we defined a Foo component with an emit method that emits an event called foo with the payload 'bar'.

Then in our template, we attached a listener to the template where we referenced our Foo component.

This is where we have:

<Foo @foo="bar = $event"></Foo>

We display assigned item in:

<p>{{bar}}</p>

Then when we click Emit, the foo event is emitted with the value 'bar'.

'bar' is assigned to $event. Then it’s set to bar in the parent component and displayed.

Whatever name we set it to, it’ll be the event name that’s used to attach event listeners. There’s no transformation of the names.

Customizing Component v-model

v-model is shorthand for @input and :value together. We can change that since Vue 2.2.0 to make v-model listen to other event names and bind to different props.

We can add the model property to our component so that v-model can listen to the event name and pass in props with names that we specify.

For example, we can write:

Vue.component("Foo", {
  model: {
    prop: "checked",
    event: "change"
  },
  data() {
    return {
      checked: false
    };
  },
  template: `
  <div>
    <label>foo</label>
    <input
      type="checkbox"
      :checked="checked"
      @change="$emit('change', $event.target.checked)"
    >
  </div>
  `
});

new Vue({
  el: "#app",
  data: {
    bar: false
  }
});

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <Foo v-model="bar"></Foo>
      <p>{{bar}}</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>

In the code above, we have:

model: {
    prop: "checked",
    event: "change"
}

to specify that the parent’s v-model directive in the parent listens to the change event and pass data for the checkbox into the checked prop.

Now we should see the value of the checkbox displayed in the p tag below the Foo component as we click the checkbox.

Conclusion

We can emit custom events with Vue with the $emit method. It takes the name of the event as the first argument, and the value we want to emit in the second argument.

Then we can listen to the event and get the payload in the parent component.

We can customize v-model by setting the prop that v-model passes the value to and then event it listens to from the child component to set the value of the specified model.