🛠️ Tiny: Multiple Props

Hey ,

I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.

Please upgrade (use this link) access this content.

I'm super eager to help you learn more!

🛠️ Tiny: Multiple Props

Total Count needs two values: The parent’s count and the child’s count. To get these two values, we need to be able to pass in two props.

One way to pass in the second prop is adding another set of [propertyName, value] pair into tiny-props.

For now, we’ll pass a childCount prop with a value of 10.

Tiny({
  // ...
  template () {
    return `
      <div
        class="component parent-component flow"
        ...
      >
		    <!-- ... -->
        <div class="half">
          <!-- ... -->
          <div tiny-component="totalCount" tiny-props="[parentCount, state.count] [childCount, 10]"></div>
        </div>
      </div>
    `
  }
})

We want to be able to get both parentCount and childCount from the props.

export default Tiny({
  template () {
    const parentCount = this.props.parentCount
    const childCount = this.props.childCount
    // ...
  }
})

To do this, we need to change the way we parse the tiny-props attribute.

New way to parse Tiny-props

If you log attribute in _addProps, you should see two pairs of props.

export default function Tiny (options) {
  // ...
  function _addProps (comp) {
    const attribute = comp.element.getAttribute('tiny-props')
    if (!attribute) return

    console.log(attribute)
    // ...
  }
  // ...
}
  • The first value in each pair is the key of the prop.
  • The second value in each pair is the value we want to pass into the prop.

We need to obtain each pair of values. The simplest way to do this is to remove all brackets and commas. This results in 4 values separated by a space.

We can remove brackets and commas with replace functions.

  • Replace [ with ''
  • Replace ] with ''
  • Replace , with ''

When we use replace we need to pass in a greedy regular expression since we want to find and replace more than one character. To add a greedy regular expression, we add a g flag at the end of the regular expression.

// Example of a greedy regular expression
const regex = /abc/g

Here are the replace functions we need. Notice we escaped [ and ] with a backslash. We do this because square brackets are used to represent something in regular expressions.

export default function Tiny (options) {
  // ...
  function _addProps (comp) {
    // ...
    const props = attribute
      .replace(/\[/g, '')
      .replace(/\]/g, '')
      .replace(/,/g, '')

    console.log(props)
    // ...
  }
  // ...
}

We can now split the string with spaces to obtain four values in an array.

export default function Tiny (options) {
  // ...
  function _addProps (comp) {
    // ...
    const props = attribute
      .replace(/\[/g, '')
      .replace(/\]/g, '')
      .replace(/,/g, '')
      .split(' ')

    console.log(props)
    // ...
  }
  // ...
}

We can make the split a bit more robust by checking for one or more spaces. We can do this one-or-more space check with a regular expression /\s+/.

  • \s signifies whitespace
  • + signifies one or more
export default function Tiny (options) {
  // ...
  function _addProps (comp) {
    // ...
    const props = attribute
      .replace(/\[/g, '')
      .replace(/\]/g, '')
      .replace(/,/g, '')
      .split(/\s+/)

    console.log(props)
    // ...
  }
  // ...
}

Odd values (1st, 3rd, 5th, etc) are keys we want to add to props while even values (2nd, 4th, 6th, etc) are values themselves.

We can loop through the array and extract these values. Here, we’ll use a for-loop so we don’t have to loop through every item. We’ll increase the index by 2 so we can skip one item with each iteration.

export default function Tiny (options) {
  // ...
  function _addProps (comp) {
    // ...

    for (let index = 0; index < props.length - 1; index = index + 2) {
      const prop = props[index]
      let value = props[index + 1]
    }

    // ...
  }
  // ...
}

We can now copy-paste the previous code we wrote to obtain the correct value into this loop. Make sure to use continue instead of return since return ends the entire _addProps function while continue only ends the current loop.

export default function Tiny (options) {
  // ...
  function _addProps (comp) {
    // ...

    for (let index = 0; index < props.length - 1; index = index + 2) {
      const prop = props[index]
      let value = props[index + 1]

      if (value.includes('.')) {
        value = value
          .split('.')
          .reduce((acc, current) => acc[current], options)
        comp.props[prop] = value
        continue
      }

      if (options[value]) {
        comp.props[prop] = options[value]
        continue
      }

      comp.props[prop] = value
    }

    // ...
  }
  // ...
}

At this point, both parentCount and childCount should both be 10.

But since we hardcoded the childCount value into a custom attribute, this value will turn into a string. This explains why total count is 1010, not 20.

The best way to resolve this problem is to pass childCount via a property. We can do it via state.childCount for example.

Tiny({
  state: {
    count: 10,
    childCount: 10
  },

  template () {
    return `
      <div
        class="component parent-component flow"
        tiny-listener="[increase-parent-count, increaseSelfCount]"
      >
        <!-- ... -->
        <div class="half">
          <div tiny-component="child"></div>
          <div tiny-component="totalCount" tiny-props="[parentCount, state.count] [childCount, state.childCount]"></div>
        </div>
      </div>
    `
  }
})

That’s it for now!

At this point you may be thinking: Why are we splitting the whole Counter thing into three components? Wouldn’t it be simpler to put everything in one component?

In this case, yes. It’s much easier to build everything as one component. But don’t forget we’re building a library that allows people to split code up into smaller parts. The example we’re working on is small and trivial. The splitting only begins to shine for larger components.