Day… 8? Catch ups! Also, doing some select input & validation in Redux Form!

Some Personal Update

Wow, been a while since I last blog. Couple of things happened:

  1. I decided to dive fully into the Udemy React course pack I got (Modern React with Redux).
  2. A friend gave me a book on algorithm to study for future interview, which I sadly could not understand. I ended up purchasing an algorithm book that I got from the library previously – I only read it half way before it was due, but I did understood it. Once finish that, I am going to give my friend’s book another crack.
  3. I found a few internship to apply, with one requiring that I start on opensource contribution, which require me to set up an opensource project’s environment in the first. For those who have a bit more experience in development, I think we all know that can go……
  4. My family decided to travel for 3 whole weeks in Japan & Hong Kong, where the last 2 week consisted of living in a tiny bedroom with no table. My neck did not appreciated the experience. While I love – love – Japan, 3 weeks of 24 hours living in extremely close quarter with anyone is a bit too much. I have never been so happy to be back in San Francisco. If I ever tell you I am going to travel with my family to Asia for over 2 week in the future, STOP ME!

*cough* Yea, it’s been a bit eventful. The fact that I got sick the week I got back doesn’t help.

Anyway, I finally got some progress. I started with the Form component. The key issues I worked on are validation and incorporating <select> tag in Redux Form. I started coding with the example code in Redux Form’s  Field-Level Validation page.

Problem A: Select Input Tag

In the example, each input element is a <Field /> component, which contains an attribute named “component”. The component attribute accepts a method, which is named renderField() in this case. Props are passed to the called method – again, renderField in this case. The renderField() method contains code that outputs <input> tag using the data in the props passed by <Field />.

The problem for me is that I wanted to output one single <select> input element, while renderField()‘s code only output <input> HTML. For those who are not familiar with HTML, select is one of the very few input element that does not use <input> as its HTML – it uses <select> and the child element <option>.

While I can hard code the <select> <option> HTML, is there a way I can use the component feature to dynamically generate out the input fields?

So there are various solutions I can tried:

1) Check Redux Form’s <input> type

Natively, <input>’s type attribute does not recognize select as possible values. But hey, you never know – maybe Redux Form’s Field component do. It’s not in the documentation either, but let’s give it a try!

Result: Nope.

2) Change <Field /> into <Field></Field>

Maybe if I put in an <option> type somewhere? But Field component in the example is self-enclosing…… Let’s try to change it into <Field></Field> and put <option> between!

Result: Nah…

3) Conditional statement in renderField()

I guess I can use conditional statement to check if the input type is select…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const renderField = ({ input, label, type, children, meta: { touched, error } }) => (

<div>
    <label>{label}</label>
    <div>
      {
        (type === "select")
        ? <select {...input}><option>Test</option></select>
        : <input {...input} placeholder={label} type={type} />
      }
      { touched && error ? <span> {error} </span> : '' }
    </div>
  </div>

)

Result: Of course it works, but the conditional statement will be check each time <Field> is rendered. I don’t want to add unnecessary complexity. My app is small, so it only have 2 input element, but I want to build it to have good maintainability if the code get bigger.

4) Add a new method, such as renderSelect()

I could put the select HTML all into a new method, used as a value for <Field />’s component attribute only when <select> is needed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const renderField = ({ input, label, type, meta: { touched, error } }) => (

<div>
    <label>{label}</label>
    <div>
      { <input {...input} placeholder={label} type={type} /> }
      { touched && error ? <span> {error} </span> : '' }
    </div>
  </div>

)
const renderSelect = ({ input, label, type, meta: { touched, error } }) => (

<div>
    <label>{label}</label>
    <div>
      { <select {...input}><option>Test</option></select>
      }
      { touched && error ? <span> {error} </span> : '' }
    </div>
  </div>

)

Result: That’s better! But…

Problem B: Option tag!

As I mentioned earlier, <option> is a child element for the <select> tag. For those unfamiliar with HTML, option is used to output the choices in an select input element. In my case, my options are: Muni, Bart, and Caltrain.

Also mentioned earlier was that <Field /> is a self-enclosing tag in the examples. My question lies in how I should insert something like option, which is a child element and is different for each select input element?

Let’s try some possible solution:

1) Hard Code:

In this case, I only have one select input type, so I can hard code the options of muni, bart, and caltrain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const renderSelect = ({ input, label, children, meta: { touched, error } }) => (

<div>
    <label>{label}</label>
    <div>
      {
        <select {...input}>
          <option value="">--None--</option>
          <option value="muni">Muni</option>
          <option value="bart">Bart</option>
          <option value="caltrain">Caltrain</option>
        </select>
      }
      { touched && error ? <span> {error} </span> : '' }
    </div>
  </div>

)

Result: … Yea, it works, but only for one select element. What am I going to do if I add more select input element in the future???

2) Change <Field/> to <Field></Field> & insert <option> between them

It didn’t work earlier during Problem B because I had hope that if I do <input type=”select”> in renderForm(), putting in <option> between <Field></Field> would somehow work due to Redux Form magic. Such magic did not exist.

But, now I have a renderSelect(), which outputs <select> HTML, will putting <option> between opening and closing Field tags work?

Result: Nope. In hindsight, if renderSelectInput() outputs <select> HTML, how would it even know to insert all the <option> tags before the closing tag of </select>?

3) Check if the props passed by <Field /> include child element data

Wait, do the props passed from <Field /> to renderField()/renderSelectForm contain data from child element?

1
2
3
4
5
6
7
8
9
10
11
const renderSelect = ({ input, label, children, meta: { touched, error } }) => (

<div>
    <label>{label}</label>
    <div>
      {  <select {...input}>{children}</select> }
      { touched && error ? <span> {error} </span> : '' }
    </div>
  </div>

)

Result: Ok, that works! Yes!

Problem C: Validation

Field component contain an attribute called validation. If the method or value called returns anything other than undefined, it knows an error have occurred and passed the returned String to the method called by components as the prop meta.error.

If you take a quick look at the example’s top section, the validation is not exactly fun to read. It is also hard coded and not flexible. So, let’s create a method for validation that generates error code more dynamically:

1
2
3
4
5
6
7
8
9
const validate = values => {
  const errors = {};

const options = ["muni", "bart", "caltrain"];
  errors.agency = (!values.agency || options.indexOf(values.agency) === -1 ) ? "Please select a valid agency" : '';
  errors.stopCode = ( isNaN(Number(values.stopCode)) || values.stopCode.length &lt; 3 || values.stopCode.length > 7 ) ? "Please enter a valid stop code" : '';

return errors;
}

And by adding valid as an argument for reduxForm(), the call to validate() would be automatic due to <a href=”https://redux-form.com/7.2.0/docs/api/reduxform.md/#-code-validate-values-object-props-object-gt-errors-object-code-optional->ReduxForm API. I don’t have to hard code in valid=valid() every single time!

1
2
3
4
5
6
7
8
9
const validate = values => {
  const errors = {};

const options = ["muni", "bart", "caltrain"];
  errors.agency = (!values.agency || options.indexOf(values.agency) === -1 ) ? "Please select a valid agency" : '';
  errors.stopCode = ( isNaN(Number(values.stopCode)) || values.stopCode.length &lt; 3 || values.stopCode.length > 7 ) ? "Please enter a valid stop code" : '';

return errors;
}

That’s a lot less chaotic, isn’t it? My next step should be the output data once form fetch the JSON, but let’s rest for now. Until next time!

Day 7: Async Testing

So, definitely haven’t been working on the app lately. It’s been another busy week – went to the Livability Award, added new features to the Sponsorlane dashboard, and attended the API World Hackthon. I ended up not the participating in the hackathon, but I got to check out some cool companies and played around with Citi’s new beta API.

React app wise, I only got to work on the async action testing, using Redux’s doc as guide. I also commented out a bunch of unfinished code so they wouldn’t interrupt when I start the test commands. As a result, the testing is working again, and I find some error in components file. The testing is also giving a false positive for the async actions, but that should change once I get the stores in and commented out a few things.

Day Six: Slower progress this week. Worked on container & prop-types.

For the last weekend, I spent the days emerge in WordCamp Sacramento 2017. It was my first WordCamp, and it was awesome!

Since I didn’t carry my macbook all the way over to Sac, I spend most of my off time studying JavaScript in my iPad. Namely Learning JavaScript Design Patterns by Addy Osmani and Modern React with Redux by Stephen Grider.

So, for me, it was more about building fundamental this weekend. Progress-wise in my app:

  • Refactored the input form from version 1 in my Nextbus Connect project to my component, Form.
  • Incorporated prop-types.
  • Worked on container with React doc as reference, adding in mapStateToProps() and connect() for the reducer.

 

Day Five: Building and Testing Redux Actions

For today, I started working on the actions file with redux’s own action documentation as reference. It seems their sample tend to favor seperating actions types and action creators into different files, but I think I favor keeping them one file for now so it is easier for me to keep track of things. I only have 3 actions types and 4 action creator for now anyway.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* action types*/
export const FETCH_REQUEST = 'FETCH_REQUEST'
export const FETCH_SUCCESS = 'FETCH_SUCCESS'
export const FETCH_FAILURE = 'FETCH_FAILURE'

/* action creators*/
export function fetchRequest() {
  return {
    type: FETCH_REQUEST
  }
}

export function fetchSuccess(body) {
  return {
    type: FETCH_SUCCESS,
    body
  }
}

export function fetchFailure(err) {
  return {
    type: FETCH_FAILURE,
    err
  }
}

fetchJSON action creator, posted as image because ${} escapes the code snippet display

I also using redux’s Writing Tests doc, so the action creators are tested. I didn’t work on the fetchJSON() one though, because there is a fetch() there, making the action create async. The doc do have a section for async action creator, but I think I will do that next.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
describe('actions.js: ', () => {
  it('should create an action to fetch request', () => {
    const requestAction = {
      type: 'FETCH_REQUEST',
    }
    expect(actions.fetchRequest()).to.eql(requestAction)
  });
  it('should create an action for successful request', () => {
    const body = 'Fetch successful';
    const successAction = {
      type: 'FETCH_SUCCESS',
      body
    }
    expect(actions.fetchSuccess(body)).to.eql(successAction)
  });
  it('should create an action for failed request', () => {
    const err = 'Fetch failed';
    const failureAction = {
      type: 'FETCH_FAILURE',
      err
    }
    expect(actions.fetchFailure(err)).to.eql(failureAction)
  });
})

Day Three: Looking at Redux Doc

So, create-react-app got started, testing environment is set up, directory is organized. Time to write more code than just test placeholder files.

It’s been over a month. so my memory of Redux is a bit blurry – but it’s ok, redux.js.org to the rescue! Reading their Todo List example and some of my old codes jogged my memory.

Here is the latest directory structure, with all the new files in. At the right is the current state of action creator, action.js.

action creater
Action Creater file, action.js

There is also a basic combineReducer in reducers/index.js. So far, the test file just check that the files in the components are outputting div. For now, I am mostly just setting up some empty functions.