Building a Cardstack app - Part 2

08 December 2017

At the end of Part 1, we managed to set up and configure the Cardstack plugins
we needed and were greeted with a “Welcome to Cardstack!” header as our reward.

Here, in Part 2, we’ll add the rental listing on the main page and create the
rental details page, learning how to use Cardstack components, search and all
the code Cardstack generates for us in the process.

Listing rentals on the main page

The first feature we’ll implement is listing the rentals on the main page and
filtering them by city.

We established that the content on the main page is rendered by the
cardstack/page-page component and we currently only have the title of the page
displayed:

As I mentioned in Part 1, Cardstack is a search-first web framework so we’re
going to trigger a back-end search to fetch the rental items. But first, let’s
install the cardstack search add-on (and then restart):

1

$ ember install @cardstack/search

Now, let’s define the search parameters for the main page. We want to fetch all
rentals on the main page, so let’s add a mainQuery property to the page to
specify this. The properties of the main page are defined in the models.js
file, so let’s edit that:

We added a main-query field that is of type object, and set it to fetch all
rentals on the main page, by only specifying the rentals type, without any
more parameters.

Integrating search results into pages

We should now add search results to the main page.

We do that by adding the cardstack-searchsmart component which will trigger
the search to the backend. In its simplest form, it takes a query object in its
query attribute that defines the search parameters.

// cardstack/seeds/development/models.jsconstFactory=require('@cardstack/test-support/jsonapi-factory');(...)functioninitialModels(){(...)factory.addResource('rentals').withAttributes({"title":"Grand Old Mansion","owner":"Veruca Salt","city":"San Francisco","property-type":"Estate","bedrooms":15,"description":"This grand old mansion sits on over 100 acres of rolling hills and dense redwood forests."});factory.addResource('rentals').withAttributes({"title":"Urban Living","owner":"Mike Teavee","city":"Seattle","property-type":"Condo","bedrooms":1,"description":"A commuters dream. This rental is within walking distance of 2 bus stops and the Metro."});factory.addResource('rentals').withAttributes({"title":"Downtown Charm","owner":"Violet Beauregarde","city":"Portland","property-type":"Apartment","bedrooms":3,"description":"Convenience is at your doorstep with this charming downtown rental. Great restaurants and active night life are within a few feet."});}

Every time we change the schema definition, we have to restart our app so that
server-side operations can take place. When we load the main page of our app
again, we see that it’s actually working, the title of each listing is
displayed:

Please notice (because it’s awesome!) that we never implemented any API
endpoints. By virtue of having defined the Rental type, Cardstack (more
precisely, the @cardstack/jsonapi package) generated those CRUD endpoints for
us.

Displaying rental properties

As a next step, let’s now display more properties for each rental in the
listing. Let’s do that by rendering a component for each search result item
instead of writing the markup inline.

The cardstack-content is the workhorse of UI customization in Cardstack. It
takes a content object for the object to be rendered and a format property
that defines how it should be rendered. The cardstack-content component then
goes on to render the component that is named cardstack/${type}-${format}.

At any rate, when we save the above template, Cardstack will tell us which
component we need to define by including its name in the error message on the
page.

So let’s create said component:

1

$ ember g component cardstack/rental-listing

And move the few lines that we had in the each loop to the component’s
template for each listing:

It all works, the rental list items now display all information correctly:

Extending generated classes

Taking a second look at our page, we notice that the ‘Sleeps’ property is not
displayed correctly, it displays “Enter undefined” instead of the number of
people the rental can sleep. Let’s fix this next.

If we take a closer look at the template, we see that {{content.sleeps}} is
rendered, where content is a rental model object. However, the Rental class
(that we inherited from the original SuperRentals app) doesn’t have a sleeps
property so it makes sense that its value is undefined.

Now, here is another thing that I really like about Cardstack.

Taking the model schema (that we defined in models.js), it automatically
generates Ember Data classes for each type in our definition. The
@cardstack/models package has a code generator that accomplishes this and
you can see these generated models if you open the app’s vendor.js and search
for 'models/generated’.

The SuperRentals app defined a Rental class so let’s rewrite this by extending
the generated model and defining the sleeps computed property therein:

If we didn’t need the sleeps CP we wouldn’t even have to have a file for the
model. Cardstack takes the power of conventions even further and saves us from
having to write boilerplate code for the models, too.

Rental details page

You might have noticed that we have a link for each rental in the list where the
href is given by a call to cardstack-url. I explained this helper in Part
1, explaining that it takes a resource type and an id to create a URL from.

Here, we use it differently, only passing in a resource object. Since that
object has an id, the URL can be generated. For a rental object with an id of
24, the URL will be /rentals/24.

Following one of the links, we transition to a URL like /rentals/1 and are
greeted with the “No such component cardstack/rental-page” error message.

By now, we know really well what should be done to fix this.

Let’s create a cardstack/rental-page component and write in its template what
we want to see on the rental (details) page. The content property will be
bound to the rental within the template:

In the next part

Other than the “static” About and Contact pages, what’s missing from the
original SuperRentals app is the displaying of rental images, toggling
between a wide and a normal image view and the city filter.