Friday 23 October 2020

How can I get a value from index.html and use it to render a second template after parsing JSON file?

I'm trying to wrap my head around gulp and modern JavaScript bundling.


I have the following (simplified) structure:

dist/
    index.html
src/
    scripts/
          main.js
          modules/
                 dispatchForm.js
    styles/  
          index.scss
    templates/
          index.pug
          partials/
                  default.pug
                  selectors.pug
gulpfile.js
data.json

In my gulpfile.js, I have:

const bundler = () => {
  return rollup({
    input: './src/scripts/main.js',
    plugins: [
      babel(pkg.babel),
      nodeResolve(),
      commonJS(),
    ],
  }).then((bundle) => bundle.write({
    file: '.tmp/bundle.js',
    format: 'umd',
    sourceMap: 'inline',
  }));
};

const uglify = () => {
  return src('.tmp/bundle.js', {sourcemaps: true})
      .pipe(plugins.uglify())
      .pipe(dest('.tmp'))
      .pipe(plugins.size({title: 'bundler minified'}));
};

const styles = () => {
  const AUTOPREFIXER_BROWSERS = [
    'ie >= 10',
    'ie_mob >= 10',
    'ff >= 30',
    'chrome >= 34',
    'safari >= 7',
    'opera >= 23',
    'ios >= 7',
    'android >= 4.4',
    'bb >= 10',
  ];

  return src([
    'src/styles/main.scss',
    'src/styles/**/*.css',
  ])
      .pipe(plugins.sassGlob())
      .pipe(plugins.sass({
        precision: 10,
      }).on('error', plugins.sass.logError))
      .pipe(plugins.autoprefixer(AUTOPREFIXER_BROWSERS))
      .pipe(dest('.tmp'))
      .pipe(plugins.if('*.css', plugins.cssnano()))
      .pipe(dest('.tmp'))
      .pipe(plugins.size({title: 'styles'}));
};

// Uses PUG as template
const templates = (env) => () => {
  return src('./src/templates/*.pug')
      .pipe(plugins.pug({locals: {
        title: pkg.title,
        description: pkg.description,
        env,
      }}))
      .pipe(dest('dist'))
      .pipe(plugins.size({title: 'templates'}));
};

const reload = (done) => {
  server.reload();
  return done();
};


const images = (env) => () => {
  const destination = env === 'deploy' ? 'dist' : '.tmp';

  return src('./src/images/**/*.{gif,jpg,png,svg}')
      .pipe(dest(destination))
      .pipe(plugins.size({title: 'size'}))
};


const serve = () => {
  server.init({
    notify: false,
    logPrefix: 'WSK',
    scrollElementMapping: ['main', '.mdl-layout'],
    server: ['.tmp', 'dist'],
    port: 3000,
  });

  watch(
    ['src/**/*.pug'],
    series(templates('development'), reload)
  );

  watch(
    ['src/styles/**/*.{scss,css}'],
    series(styles, templates('development'), reload)
  );

  watch(
    ['src/scripts/main.js', 'src/scripts/**/*.js'],
    series(bundler, templates('development'), reload)
  );

  watch(
    ['src/images/**/*.{gif,jpg,png,svg}'],
    series(images('development'), templates('development'), reload)
  );
};

const clean = () => del(['.tmp', 'dist/*', '!dist/.git'], {dot: true});

exports.default = series(
    clean,
    bundler,
    uglify,
    styles,
    templates('deploy'),
    images('deploy')
);

exports.serve = series(
    bundler,
    styles,
    templates('development'),
    images('development'),
    serve
);

The way I understand it, after cleaning the files, the bundler will:

  • Serve a html page in dist folder after compiling from my sources main.js, dispatchForm.js, scss and pug templates.

Main.js

import dispatchForm from './modules/dispatchForm';

const domContentLoad = (fn) => {
  if (document.readyState !== 'loading') fn();
  else document.addEventListener('DOMContentLoaded', fn);
};

domContentLoad(() => {
  dispatchForm();
});

dispatchForm.js

const button = document.querySelector('[data-calculator-button]');

function updateValue() {
  const gain  = document.querySelector('[data-calculator-form][name="gain"]:checked');
  const cost  = document.querySelector('[data-calculator-form][name="cost"]:checked');

  if (gain && cost) {
    button.removeAttribute('disabled');
    button.classList.remove('selectors__button--inactive');
  } else {
    button.setAttribute('disabled', '');
    button.classList.add('selectors__button--inactive');
  }
}

function dispatchForm() {
  const radioInput = document.querySelectorAll('[data-calculator-form]');
  radioInput.forEach(element => element.addEventListener('input', updateValue));
}

export default dispatchForm;

selectors.pug

...

.selectors__form
    .selectors__radio
      input.selectors__input(type='radio' id='gain-points' name='gain' value='points' data-calculator-form)
      label.selectors__label(for='gain-points')

    .selectors__radio
      input.selectors__input(type='radio' id='gain-money' name='gain' value='money' data-calculator-form)
      label.selectors__label(for='gain-money')

.selectors__form
for value in [70, 80, 90, 100, 110, 120, 130]
  .selectors__radio
    input.selectors__input(type='radio' id=`have-${value}` name='cost' value=value data-calculator-form)
    label.selectors__label(for=`have-${value}`)
      | Até 
      b= ` C$${value}`

button.selectors__button.selectors__button--calculate.selectors__button--inactive(disabled=true data-calculator-button)
...

The above creates some selectors for 'cost' or 'gain' from selectors.pug, main.js and dispatchForm.js, via gulps 'bundler', and renders it as html.


But now I would like to:

  1. Use one of the two button submitted values (${value}) and pass it as an argument to a function that will parse a JSON file.

  2. Finally, the parsed JSON result will be passed to another pug file


QUESTION

  1. How do I get this JSON (from dispatchForm.js? from gulpfile.js? from pug natively?) and pass it to another pug template?

  2. Should JSON fetching be dealt with on separate js module, since displayed JSON will be rendered on a separate html page, using another pug template partial? How so?


gulp-data

I also learned that there are packages like gulp-data, used to handle json data, and I don't know if they are the way to go here.


Also, this SO question hints as how to pass pug JSON objects to client side Javascript.


Can anyone point me in the right direction? Any help would be much appreciated.



from How can I get a value from index.html and use it to render a second template after parsing JSON file?

No comments:

Post a Comment