How to create a scheduler with with Electron, Vue and node-schedule
Tags: electron, vue, node, javascript
Published: 2020-08-12 00:43:58

Hello, my name is [Nick Gottschlich](https://twitter.com/NickGottschlich), and I am the creator of [Social Amnesia](https://github.com/Nick-Gottschlich/Social-Amnesia), an Electron/Vue application to help you delete your reddit and twitter content. One feature of this application is scheduling daily runs:

![Social Amnesia daily schedule feature to remove twitter content](https://dev-to-uploads.s3.amazonaws.com/i/kc1znkk12pcq22g6lvsb.png)

If you're interested in how this was created, and how to create your own scheduling tool with Electron and Vue (think for an alarm clock, a daily reminder, a message scheduler, etc.), then read on!

--

If you haven't already set up your own Electron/Vue app, there are a few short steps to do that, using the vue CLI (command line interface).

`npm install -g @vue/cli`
`vue create electron-vue-node-scheduler`
_I like to use class-style component syntax, so to follow along with my code, select "typescript" and "Use class-style component syntax"_
`cd electron-vue-node-scheduler`
`vue add electron-builder`

Now, let's build prototype a simple component that will act as our user interface. We can use [Vue Bootstrap](https://bootstrap-vue.org/) to speed up development.

Install with `vue add bootstrap-vue`.

Now, we can start up our app with `yarn electron:serve`.

Alright, now we can build the actual component.

--

You new boilerplated Electron/Vue app comes with a convenient HelloWorld.Vue component which we will be modifying to be our scheduler component.

Go ahead and copy paste this code over everything that was in HelloWorld.Vue:

```javascript
<template>
  <div>
    <b-time
      v-model="value"
      locale="en"
      @context="onContext"
    ></b-time>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class HelloWorld extends Vue {}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
```

The b-time here is the [bootstrap-vue time component](https://bootstrap-vue.org/docs/components/time#time).

We now have set up an easy to use and good looking time selector component. Go ahead and play around with it:

![Time Selector component](https://dev-to-uploads.s3.amazonaws.com/i/flqu9d11e3236cd3nj3p.png)

Great, now let's get the actual time out of this so we can use it for our scheduler.

Here's how you will update your class component:

```javascript
export default class HelloWorld extends Vue {
  value = '';

  onContext(context) {
    console.log('context value', context.value);
  }

  data() {
    return {
      value: this.value,
    };
  }
}
```

Now, we are keeping track of the value using [Vue's data function](https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function) and we will get an update through `onContext` whenever the time picker is changed by the user:

![Time picker changed by user, console.log updated to show value in string format '19:12:00'](https://dev-to-uploads.s3.amazonaws.com/i/wrvw91bitcdl5aevjwbo.png)

Great, now we can set up our scheduler. We will use [node-schedule](https://github.com/node-schedule/node-schedule#readme) for this.

`yarn add node-schedule`

Then in your <script> add a `import schedule from "node-schedule";`.

Then update your component like so:

```javascript
export default class HelloWorld extends Vue {
  value = '';

  // eslint-disable-next-line @typescript-eslint/no-empty-function
  scheduleJob = schedule.scheduleJob('* * * * *', () => {});

  onContext(context) {
    // get hours and minutes off of something like '19:12:00'
    const hours = context.value.split(':')[0];
    const minutes = context.value.split(':')[1];

    this.scheduleJob.cancel();
    this.scheduleJob = schedule.scheduleJob(
      `${minutes || '00'} ${hours || '00'} * * *`,
      () => {
        console.log('job ran on schedule!');
      },
    );
  }

  data() {
    return {
      value: this.value,
    };
  }
}
```

Okay, this is getting a bit more confusing. Let's break it apart:

`scheduleJob = schedule.scheduleJob('* * * * *', () => {});` This creates a local scheduleJob we can reference. We need to keep track of this, because any time the time is updated, we are going to cancel any previously scheduled jobs and create a new scheduled job.

If the asterisks are confusing you, that's [cron-style scheduling](https://github.com/node-schedule/node-schedule#cron-style-scheduling):

![cron style scheduling](https://dev-to-uploads.s3.amazonaws.com/i/xugukl05tmyvv11oofl6.png)

Now, onContext (meaning whenever the user changes the time schedule component), we will get a string in the format of 'HH:MM:SS'. We want to break up this string to get hours, and minutes, which we do with the split function: `const hours = context.value.split(':')[0];`

Finally, we `cancel` the previous scheduled job, and create a new one at the time the user has now decided:

![screenshot showing job ran on schedule](https://dev-to-uploads.s3.amazonaws.com/i/60yngargkfuieadba7z1.png)

Great, that's it! You now have everything you need to build your own scheduler app! And how cool is this, since it's in electron, it's a native app that will run on Windows, Mac and Linux!

Next I would recommend looking into Electron's [Tray functionality] (https://www.electronjs.org/docs/api/tray) so that you can minimize the app to the tray instead of closing it, so your scheduled job will still run at the right time while the app is running in the background.

Here is the [GitHub Repo](https://github.com/Nick-Gottschlich/electron-vue-node-scheduler) that you can look at if you want to see the code I used in this post.