Use `//@ts-check` in Visual Studio Code to Find Undeclared Variables (and save yourself hours of hunting)

Oh. My. God!

I just discovered //@ts-check in Visual Studio Code.

For all the web/JavaScript developers out there, add that comment to the top of your .js file in Visual Studio Code (that’s all you have to do).

Now, any issues in you variables (like using variables you haven’t declared) will show as an error in the IDE.

This is what I call super charging your IDE and your development.

I could have saved myself half a day’s work yesterday if I’d thought to search for “visual studio code undeclared javascript variables” beforehand. ?‍♂️

See: https://code.visualstudio.com/docs/nodejs/working-with-javascript#_type-checking-javascript

JavaScript (ES2015) – Handling Promises in a loop (full working example)

I’ve spent the best part of the last day and half working with a simple Promise problem in JavaScript.

The scenario I have is:

  • I have a tree structure of folders (and sub-folders) with documents in them.
  • The production scenario I’m emulating is to submit each item in the tree (both folders and documents) to an API for saving, and to receive a return object with a new ID.
  • Documents are are associated with folders via IDs (e.g. Document.FolderID = Folder.ID and Folder.ParentID = Folder.ID).
  • Each item is added to an array of data in my JavaScript app.

The heart of this problem is the asynchronous call to the API. Because I need to associate documents with folders, and sub-folders with parent folders, I need to process each folder and wait for the response to get the new ID before processing sub-items.

Old school, this was done with callback (and I still use callback to this day). But in the interest of staying “modern” I took the ES2015 Promise approach.

Another thing to factor in is the loop through folders and items in the tree. I chose the for(let i; ..; ..) approach to pluck items out of the arrays in the tree. However, you can’t just call the api within the for loop because by the time an async finishes executing and you’re ready to process the next item,. the loop could have iterated on, changed the value of the iterator (i in this example) and hence the currently item in the array.

So you need to wrap the call the API in another function to localise the scope of the variables.

At the end of processing the tree I also need to tell the calling function everything is complete. Which means tracking the completion status of all promises in the loop and notifying the caller of overall completion only once all branches are finished (using Promise.all()).

Anyway, I created a fully working Pen at https://codepen.io/jsnelders/pen/LYVJQbG to demonstrate how this works.
I suggest you pop it open in CodePen itself to see the results – open the browser console (not the CodePen Console) to view debug output.

See the Pen
JavaScript (ES2015) – Handling Promises in a loop
by Jason (@jsnelders)
on CodePen.

JavaScript (ES2015) Promise error “Uncaught (in promise) {reject message}”

Debugging asynchronous code is difficult. Even Promises can become complex.

And once again my Golden Rule of Programming rings true: “if you think something should work but it doesn’t, you probably have a spelling mistake!

 

I’m working on a simple script to test JavaScript Promises – specifically, handling Promises in loops, and dealing with functions that both handle and return promises.
I’ll post about that later when I’m done.

For now, I just spent the last hour trying to figure out why I was getting a JavaScript console error Uncaught (in promise) processItems(Folder: 1): Reject caught (the part in italics is just a message returned in a reject(“processItems(” + title + “): Reject caught”)).

 

The console looks like this:

 

And the problem code is:

executeFolder(item, parentFolder) 
{
    let promise = new Promise(function (resolve, reject) {

        _this.asyncFunction(item)
        .then((resultItem) => {
            _this.processItems(item, resultItem).then(() => {
                resolve("executeFolder.then(" + parentFolder.title + ")");
            });
        })
        .catch( (e) => {
            reject("executeFolder.cathch(" + parentFolder.title + ")");
        });
    });

    return promise;
}

 

The problem is the line in bold: _this.asyncFunction(item).

I hadn’t defined the variable _this (I’d extracted this function out of another function which did have the definition).

All I had to do was define _this and the error resolved.

 

Once gain it was a spelling error (in this case not spelling anything at all).

I stopped feeling bad about these sorts of errors long ago. I’ve learnt over the years we (as developers) get a kind of blindness or tunnel vision when working on problems like this. Between having to hold the business problem, processing logic, nested functionality and all the other bits in our head, we can easily blank out what we later think was “staring us in the face”.

That’s where a good IDE comes in that can track unused variables.
I’m using Visual Studio Code which does identify unused variables (in fact, I noticed and removed one in the project no long ago) but for some reason it failed me in this instance.

Vue.js 2.x with global store and reactive component data sync

This is a basic test to show how you can use a global object as your primary data store in Vue.js, and use a watcher to trigger a function that builds secondary data sets filtered from the primary source to update the display in the Vue instance (or component).

In this way you can share data between the Vue instance and components (via the global object) and work with the data specifically need by a component while still responding to changes in the global store (e.g. if the global data is updated via a service class or AJAX call).

If the embed below is not working then view it on CodePen at https://codepen.io/jsnelders/pen/dyoJPrw.

 

See the Pen
Vue.js with global store and component reactive sync test
by Jason (@jsnelders)
on CodePen.

 

 

Add Disqus comments form to Vue.js App or Component

I haven’t used with Disqus much, when following the instructions you just need to add code like the following to your page to display the comments form.

 

<div id="disqus_thread"></div>
<script>
/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://jasonsnelders-dev.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>

 

But when you try to add this within a Vue application instance or component, you receiving an error like:

 

Errors compiling template: Templates should only be responsible for mapping the state to the UI. 
Avoid placing tags with side-effects in your templates, such as <script>, as they will not be parsed.

 

If you Google for the problem “embed disqus in vue” or similar  it might seem the only solution is to install yet another bloody package from npm or yarn.

Fear not, the solution is actually quite simple.

 

Simply move the JavaScript into the Vue mount() event and it should work fine. Don’t forget to delete the actual <script> and </script> elements from your HTML.

The following is a copy of an actual Single File Component I created in a project. Unnecessary content has been removed:

 

<template>
    <div>
        <p>Leave a comment, ask a question or just say hello.</p>
        <div id="disqus_thread"></div>
        <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>  
    </div>
</template>

<script>

export default {
    name: "ContactContent",

    mounted: function()
    {
        /**
        *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
        *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/
        /*
        var disqus_config = function () {
        this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
        this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
        };
        */
        (function() { // DON'T EDIT BELOW THIS LINE
        var d = document, s = d.createElement('script');
        s.src = 'https://jasonsnelders-dev.disqus.com/embed.js';
        s.setAttribute('data-timestamp', +new Date());
        (d.head || d.body).appendChild(s);
        })();
    },
}
</script>

Cheers!

Webpack error “The operation was rejected by your operating system.”

I just tried installing webpack via npm in a new project and received the following. Notice the error in below near the end:

 

PS D:\Workspaces\profile-jsnelders-com> npm install webpack webpack-cli --save-dev
npm ERR! path D:\Workspaces\profile-jsnelders-com\node_modules\brorand\package.json.1891953989
npm ERR! code EPERM
npm ERR! errno -4048
npm ERR! syscall rename
npm ERR! Error: EPERM: operation not permitted, rename 'D:\Workspaces\profile-jsnelders-com\node_modules\brorand\package.json.1891953989' -> 'D:\Workspaces\profile-jsnelders-com\node_modules\brorand\package.json'
npm ERR!  { Error: EPERM: operation not permitted, rename 'D:\Workspaces\profile-jsnelders-com\node_modules\brorand\package.json.1891953989' -> 'D:\Workspaces\profile-jsnelders-com\node_modules\brorand\package.json'
npm ERR!   cause:
npm ERR!    { Error: EPERM: operation not permitted, rename 'D:\Workspaces\profile-jsnelders-com\node_modules\brorand\package.json.1891953989' -> 'D:\Workspaces\profile-jsnelders-com\node_modules\brorand\package.json'
npm ERR!      errno: -4048,
npm ERR!      code: 'EPERM',
npm ERR!      syscall: 'rename',
npm ERR!      path: 'D:\\Workspaces\\profile-jsnelders-com\\node_modules\\brorand\\package.json.1891953989',
npm ERR!      dest: 'D:\\Workspaces\\profile-jsnelders-com\\node_modules\\brorand\\package.json' },
npm ERR!   stack: 'Error: EPERM: operation not permitted, rename \'D:\\Workspaces\\profile-jsnelders-com\\node_modules\\brorand\\package.json.1891953989\' -> \'D:\\Workspaces\\profile-jsnelders-com\\node_modules\\brorand\\package.json\'',
npm ERR!   errno: -4048,
npm ERR!   code: 'EPERM',
npm ERR!   syscall: 'rename',
npm ERR!   path: 'D:\\Workspaces\\profile-jsnelders-com\\node_modules\\brorand\\package.json.1891953989',
npm ERR!   dest: 'D:\\Workspaces\\profile-jsnelders-com\\node_modules\\brorand\\package.json',
npm ERR!   parent: 'profile-jsnelders-com' }
npm ERR!
npm ERR! The operation was rejected by your operating system.
npm ERR! It's possible that the file was already in use (by a text editor or antivirus),
npm ERR! or that you lack permissions to access it.
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though this is not recommended).

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\jsnel\AppData\Roaming\npm-cache\_logs\2020-02-06T20_06_02_861Z-debug.log
PS D:\Workspaces\profile-jsnelders-com> npm install webpack webpack-cli --save-dev
+ webpack@4.41.5
+ webpack-cli@3.3.10
added 10 packages from 6 contributors, updated 1 package and audited 8965 packages in 9.19s
found 0 vulnerabilities

PS D:\Workspaces\profile-jsnelders-com>


npm ERR! the command again as root/Administrator (though this is not recommended).

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\jsnel\AppData\Roaming\npm-cache\_logs\2020-02-06T20_06_02_861Z-debug.log

 

I just re-ran the npm install ... again and it worked fine the second time. As the message suggests, it was probably a system process in Windows locking the file the first time.

CSS Stacked Paper Effect with Fade Out Transition

A little project I started late tonight.
I want to create a web page that looks like it has a stack of paper, where you can “flip away” the top page after you finish reading it. Similar to a “flip book” (see turn.js as an example) but having only a single page showing at a time (vs the 2-page “open book” every other solution goes with).

 

I found the CodePen https://codepen.io/mlms13/pen/LKFoy which I forked as a starter for the version I’m now developing:

(Link: https://codepen.io/jsnelders/pen/xxGKBpv)

I still have a few features to add:

  • Page curl at the top right (possibly).
  • Responsive design for different screen sizes. I’m not sure what I’m going to do about that at the moment.
  • External forward and back controls.
  • List all pages (or pages already read) so you can quickly go back.
  • Give pages a title, and an optional number.

I’ll continue to work on this over the coming days and provide updates here.
(Yeah… that didn’t happen)

Export all core WordPress data (posts, pages, attachments, comments, tags, categories and users) to a JSON formatted file.

I created a small WordPress plugin you can use to export all your core WordPress data to JSON formatted file.

Exported data includes:

  • Posts (status: publish, private, draft)
  • Pages (status: publish, private, draft)
  • Attachments (media)
  • Comments (approved)
  • Tag definitions
  • Category definitions
  • Users

The file is generated in /wp-content/export.json in your WordPress site (note: it will be available for anyone to access).

Simple create a new page in your site, add the shortcode and run the page to generate the file.
I suggest removing the page and deleting the export.json once you’re finished with it.
This is just intended as a quick and easy way of exporting your site data to a JSON file.

Note: It may degrade performance or result in a page timeout for large sites.

Complete plug-in source code at https://gist.github.com/jsnelders/fd22ebc26530468125ffed2d5d1eb279.

Feel free to adapt the script as needed.

Code to convert exported Chrome bookmarks HTML to JSON

When you can’t find an existing solution to do something “simple” like convert an exported Google Chrome bookmarks HTML to JSON, it helps to be a programmer so you can build your own.

Check out my public GitHub code repository at: https://github.com/jsnelders/chrome-bookmarks-converter

I also have it running live at: https://chrome-bookmarks-converter.netlify.com/

It’s quick and dirty and only took a couple of hours but it work.

[Vue warn] and browser caching

(Relates to: VueJS 2.x)

I just modified a VueJS project and received the following warning:

[Vue warn]: Error in mounted hook: "TypeError: Cannot read property 'id' of null"

found in

---> <Anonymous>
<Root>

 

I’d split code from 1 JavaScript (JS) and 1 corresponding HTML page into 2 JS and HTML files.

After refreshing the page, I received the above error.

 

There was no problem in my code.

The problem was I needed to do a hard refresh in the browser get and execute and the new and updated files.