List Item Components

Like React, etc, Vue is components all the way down. Unlike Angular or Ember there is no deeper base structural abstraction like a Route or Module. In the case of Angular this is where service injection is set up, in Ember the route is where the model hook is the logical place for things like data access. Vue has no such concept, making all components relatively equal in scope.

The practise in other frameworks has been pretty simple. Replace out the iteration through a list item with an equivalent iteration over a child component.

It’s about here that Vue fell apart for me. Initially I got some strange errors on passing in properties and decided to skip it for a bit and focus on some basic layout first. I started off using VueAwesome, the Vue components for Font Awesome, and to be honest it was a disaster. I expected them to function a lot like Ember-Font-Awesome, which lets you do things like this.

{{fa-icon

(if item.checked "check-square-o" "square-o")

fixedWidth="true"

click=(action 'checkItem' item)

class="pull-right"

}}

In the above component, the icon is bound to the checked state inline. Events are bound to the icon directly, which makes for a nicely self-contained element. This is the full “advanced” mode, by the way, it could also be used as simply as {{fa-icon 'times'}} .

I assumed and expected similar levels of functionality and ended up with a lot of duplicated markup with v-if and v-if! on them, and had to put the events on a parent element. It turned out to be much easier to abandon it and just use normal HTML. Vue has excellent support for reactive classes.

<i class="fa fa-fw" :class="{'fa-check-square-o': item.checked, 'fa-square-o': !item.checked}" @click="checkItem"></i>

Again, the icon has a direct action. I quite like Vue’s event binding syntax, by the way. It is a clean, clear pattern. The event being bound is obvious, and the name of the function is clear. It’s an abstraction over the function binding used in other frameworks, especially React’s onClick={() => this.checkItem()} . It’s actually most like Ember, {{action 'checkItem'}} . It also supports some useful shortcuts like @click.prevent to tack a preventDefault onto the event, or @click.once to only allow the event to occur one time. Handy.

In any case, using VueAwesome was a mis-step and goes to show that not all tools actually really help. Sometimes a shortcut has the opposite effect.

The next step was making the buttons and events work, in particular turning the local state isEditing on and off. Turning it on wasn’t difficult, but for some reason, the button to turn it off just would not work.

I don’t honestly know what issue I found. I had a JS Fiddle and everything that conclusively proved it failed, and a Reddit thread where I asked and people confirmed the issue. Now, however, I can’t seem to make it fail. Perhaps it really was a browser bug? It took me a long time to fix this one. It’s hard to know if this was a Vue issue, a browser issue that’s kind of Vue’s fault, a browser issue Vue has no blame for, or a Chair-to-Keyboard Interface Error of some kind.

Whatever it was I got stuck on this issue for about two weeks. It was the single most baffling “stuck” I had in this whole project.

When I finally solved it by rewriting the markup in subtle ways, I ended up back at the red errors in the console I ignored before.

One of the things that confuses me most about Vue are the number of ways you can do things. Not advanced syntax, but basic structures.

A lot of people would say this is a feature, but I disagree. For a start it makes documentation incredibly difficult to follow. For example, all the documentation covers using Vue in a global, ES5 style. But the Vue CLI app builds its components using Single File Components. This makes it a bit hard to see how the parts are supposed to go together. The section of the docs on components, for example, look absolutely nothing like my components.

Key workflows are surprisingly unclear. Like… how do you pass in a property to a component? Vue’s documents say this.

<todo-item v-bind="todo"></todo-item>

Literally copied from the documentation. Well that makes sense. But… that’s only without an iterator. If we’re doing an iteration through a list of items it shows this:

<todo-item

v-for="(item, index) in items"

v-bind:item="item"

v-bind:index="index"

v-bind:key="item.id"

></todo-item>

Oh, I should say up front that not all frameworks let you actually put an iterator directly on the component, and that I like that you can in Vue.

Anyway, to my understanding, the v-bind part of that is actually optional, so we could simplify that down to :item="item" , which cuts some noise. Index isn’t strictly needed, but the key is and that’s fine. (It’s common in iterators in modern frameworks as it helps them track changes.)

<todo-item v-for="item in items" :item="item" :key="item.id" />

That’s pretty manageable, and makes sense.

Updating and Creating

The only problem with this is that it’s completely not useful. You can pass in properties like that. But if you do so you can’t actually do anything with them.

I’m reminded again of the quote from Rob Eisenberg I referenced in my React article.

React is much better for read only apps. It’s more difficult for input intensive apps. — Rob Eisenberg

The same applies for Vue, in my experience.

Inside of a Vue component you have an array of “props”, defined properties that can be passed in. You also have (as mentioned) a state object containing the local state properties. None of this is atypical or a problem, but here’s where it gets weird.

You cannot in Vue have an prop that is also a state element. So… if you want a name, you can’t pass in a name. If you want a project you can’t pass in a project. Obviously.

This is what I expected as the component.

export default {

name: 'todo-item',

props: ['item', 'currentItem'],

data() {

return {

item: this.item,

isEditing: false

}

}

}

This seems like a logical component to match up with the above component invocation. A few things don’t work as expected though, and this took me some time to fix.

One of them I’m still not sure of. I’m calling <todo-item /> but it doesn’t seem to matter what the name property actually is. I tried todo-item, TodoItem, and a few similar things and it wasn’t affected. Then purple-monkey , underpants-gnomes , and itWasTheWorstOfTimes . It made no difference. I’ve seen this happen when what was actually occurring was that webpack wasn’t properly rebuilding, so that may have been it.

The main issue I had though was this big red error.