loading...

Load specific JS files in Elixir and Phoenix

ricardoruwer profile image Ricardo Ruwer Updated on ・2 min read

First of all, I'd like to say that this post is based on that one:
http://codeloveandboards.com/blog/2016/04/26/page-specific-javascript-in-phoenix-framework-pt-2/
But I made some changes to (IMO) simplify it...

So, let's start:

First, we can add in our file assets/js/app.js this code:

// Import specific page views
import './views/init';
Enter fullscreen mode Exit fullscreen mode

And now we'll create this init.js file in assets/js/views/init.js and add this code:

import loadView from './loader';

function handleDOMContentLoaded() {
  const viewName = document.body.dataset.jsViewPath;

  const view = loadView(viewName);
  view.mount();

  window.currentView = view;
}

function handleDocumentUnload() {
  window.currentView.unmount();
}

window.addEventListener('DOMContentLoaded', handleDOMContentLoaded, false);
window.addEventListener('unload', handleDocumentUnload, false);
Enter fullscreen mode Exit fullscreen mode

And now we'll create this loader.js file mentioned on the import, so create the file assets/js/views/loader.js and add this code:

import MainView from './main';

export default function loadView(viewPath) {
  if (!viewPath) return new MainView();

  const ViewClass = require('./' + viewPath);
  return new ViewClass.default();
}
Enter fullscreen mode Exit fullscreen mode

And now this other file called main.js in assets/js/views/main.js with this code:

export default class MainView {
  // It will be executed when the document loads...
  mount() { }

  // It will be executed when the document unloads...
  unmount() { }
}
Enter fullscreen mode Exit fullscreen mode

Nice! :)
Now in our controller, we can return a new value to the view, informing the directory of our js file, something like this:

conn
|> assign(:js_view, "posts/index")
|> render("index.html")
Enter fullscreen mode Exit fullscreen mode

And now in our layout file, that may be in templates/layout/app.html.eex we can add this code in our <body> tag:

<body data-js-view-path="<%= assigns[:js_view] %>">
Enter fullscreen mode Exit fullscreen mode

And it's ready! :)
So, we'll only try to fetch the JS file is we set the js_view on the controller.

Now, to use it, you can create a file in assets/js/views/posts/index.js and add code similar to this:

import MainView from '../main';

export default class View extends MainView {
  mount() {
    // Add your JS code here...
    console.log('UHULL! It works!')

    super.mount();
  }

  unmount() {
    super.unmount();
  }
}
Enter fullscreen mode Exit fullscreen mode

Discussion

pic
Editor guide
Collapse
popo63301 profile image
Sofiane Baddag

Does this mean that for each request, a JS file is generated? Or is it pre-generated with Webpack?

I don't seem to get it completely.

Collapse
ricardoruwer profile image
Ricardo Ruwer Author

You will have an app.min.js file that was generated by Webpack and contains all your JS code.

But the idea of this guide is to have some kind of rule in our JS code that is similar to this:

if (myCurrentPage == "/contact") {
  // execute this piece code...
}

if (myCurrentPage == "/about-us") {
  // execute this other piece of code...
}

So we'll not execute code that is not necessary for some pages...

There's also a great library that I use sometimes and do almost the same thing: github.com/lucasmazza/page.js

Collapse
popo63301 profile image
Sofiane Baddag

Oh okay ! I thought the idea was to create a JS file for each page. Makes sense now !

Thanks Ricardo !