Content Fragment preview

AEM Headless applications support integrated authoring preview. The preview experience links the AEM Author’s Content Fragment editor with your custom app (addressable via HTTP), allowing for a deep link into the app that renders the Content Fragment being previewed.

Transcript
In this video, we’ll take a look at how authors can have a in-app preview experience while authoring content fragments. We’ll be using the Weekend app, which is a simple React app that connects to AM over the AM headless GraphQL APIs and displays weekend adventures, which are modeled by content fragments in AM created from the adventure content fragment model. What we’ll do is configure AM to pull up this view of any weekend adventure based on the weekend adventure that is being authored. It’s worth noting that for in order this to work, you need to have a version of your application deployed that can connect to the AM author service since this is where content authoring happens. Here I’ve deployed a version of the app to preview.app.weekend.site on port 3000 that connects to the AM author service using service credentials. Let’s get started. The first thing we’ll need to do is head over to AM and locate the content fragment model for the content fragments that we want to preview. We’ll head to Tools, General, Content Fragment Models. Since these are all in our Weekend Share project, we’ll navigate into this. Since we want to preview adventures, let’s select our adventure content fragment model and open its properties. In its properties, down at the bottom, we have a field, default preview URL pattern. This is going to be a URL to our preview application that will display our adventure content fragment. Typically, this is a natural route within our application that our end users also navigate to. But depending on your use cases, you could of course always create special author only routes within your application that are used for previewing. Let’s go ahead and use our Weekend Apps normal adventure route as the preview URL. We’ll head back to our app. Since this is the apps view that we want to use to preview our adventures, we can start by looking at this URL. Essentially, what we want to do is recreate this URL and parameterize the path to the content fragment to display. For instance, to display the details for our Bali surf camp, our application has been developed to serve this from slash adventure and then the full path to the content fragment to display. You can see we have content, dam weekend shared, en adventures, bali surf camp slash bali surf camp. If we go to a different adventure, you can see that path changes as well. Let’s go ahead and just copy and paste this URL, bring it back to our content fragment model, and paste it in. Now we have a starting point. But what we want to do is make sure that the part of the URL that changes based on the content fragment being loaded is dynamic, and that’s where AM provides expressions. There are a few expressions available. We can use the content fragment’s path, the content fragment model’s path, content fragment model’s name, the content fragment variation, or the content fragment’s ID. Since we’ve developed our app to display the adventure based on the content fragment adventure path, let’s go ahead and use that expression. We’ll go ahead and delete this and replace it with the expression. Now when we open up any adventure content fragment for editing, we’ll have a preview button that will link to this URL and replace the dollar sign curly brace content fragment dot path and curly brace with the full path of that content fragment. Let’s go ahead and try this out. Save our changes. Head back to AM. Open content fragments. Let me go ahead and filter by adventures. And let’s pick a new adventure. So now we have a preview button here in the top right. And if we click it, it opens a new tab that takes us to the adventure details view of our app. And it populates the URL to a reference to the content fragment being edited. As you can see here, it’s opened this up to our Napa wine tasting adventure details view. So as an author, I can go back to AM, make some changes to our adventure or rename it. And let’s maybe give it a new image. This looks good. And as you can see, our changes have been auto saved. So now when we click preview, it’ll take us back. We can do a hard refresh. And now we have all our changes reflected in our preview app directly linked from AM author. After previewing these changes in app, I now have confidence to publish our changes to our live application.

To use Content Fragment preview, several conditions must be satisfied:

  1. The app must be deployed to a URL accessible to authors
  2. The app must be configured to connect to AEM Author service (rather than the AEM Publish service)
  3. The app must be designed with URLs or routes that can use Content Fragment path or ID to select the Content Fragments to display for preview in the app experience.

Preview URLs

Preview URLs, using URL expressions, are set on the Content Fragment Model’s Properties.

Content Fragment Model Preview URL

  1. Log in to AEM Author service as an Administrator
  2. Navigate to Tools > General > Content Fragment Models
  3. Select the Content Fragment Model and select Properties form the top action bar.
  4. Enter the preview URL for the Content Fragment Model using URL expressions
    • The preview URL must point to a deployment of the app that connects to AEM Author service.

URL expressions

Each Content Fragment Model can have a preview URL set. The Preview URL can be parameterized per Content Fragment using the URL expressions listed in the table below. Multiple URL expressions can be used in a single preview URL.

URL Expression
Value
Content Fragment path
${contentFragment.path}
/content/dam/wknd-shared/en/adventures/surf-camp-bali/surf-camp-bali
Content Fragment ID
${contentFragment.id}
12c34567-8901-2aa3-45b6-d7890aa1c23c
Content Fragment variation
${contentFragment.variation}
main
Content Fragment Model path
${contentFragment.model.path}
/conf/wknd-shared/settings/dam/cfm/models/adventure
Content Fragment Model name
${contentFragment.model.name}
adventure

Example preview URLs:

  • A preview URL on the Adventure model could look like https://preview.app.wknd.site/adventure${contentFragment.path} that resolves to https://preview.app.wknd.site/adventure/content/dam/wknd-shared/en/adventures/surf-camp-bali/surf-camp-bali
  • A preview URL on the Article model could look like https://preview.news.wknd.site/${contentFragment.model.name}/${contentFragment.id}.html?variation=${contentFragment.variation} the resolves https://preview.news.wknd.site/article/99c34317-1901-2ab3-35b6-d7890aa1c23c.html?variation=main

In-app preview

Any Content Fragment using the configured Content Fragment Model, has a Preview button. The Preview button opens the Content Fragment Model’s preview URL and injects the open Content Fragment’s values into the URL expressions.

Preview button

Perform a hard refresh (clearing the browser’s local cache) when previewing Content Fragment changes in the app.

React example

Let’s explore the WKND App, a simple React application that displays adventures from AEM using AEM Headless GraphQL APIs.

The example code is available on Github.com.

URLs and routes

The URLs or routes used to preview a Content Fragment must be composable using URL expressions. In this preview-enabled version of the WKND app, the adventure Content Fragments are displayed via the AdventureDetail component bound to the route /adventure<CONTENT FRAGMENT PATH>. Thus, the WKND Adventure model’s Preview URL must be set to https://preview.app.wknd.site:3000/adventure${contentFragment.path} to resolve to this route.

Content Fragment preview only works if the app has an addressable route, that can be populated with URL expressions that render that Content Fragment in the app in a preview-able manner.

  • src/App.js
...
function App() {
  return (
    <Router>
      <div className="App">
        <header>
            <Link to={"/"}>
                <img src={logo} className="logo" alt="WKND Logo"/>
            </Link>
            <hr />
        </header>
        <Routes>
          {/* The route's path must match the Adventure Model's Preview URL expression. In React since the path has `/` you must use wildcards to match instead of the usual `:path` */}
          <Route path='/adventure/*' element={<AdventureDetail />}/>
          <Route path="/" element={<Home />}/>
        </Routes>
      </div>
    </Router>
  );
}

export default App;

Display the authored content

The AdventureDetail component simply parses the Content Fragment path, injected into the Preview URL via the ${contentFragment.path} URL expression, from the route URL, and uses it to collect and render the WKND Adventure.

  • src/components/AdventureDetail.js
...
function AdventureDetail() {

    // Read the `path` value which is the parameter used to query for the adventure's details
    // since the params value captures the `*` wildcard in `/adventure/*`, or everything after the first `/` in the Content Fragment path.
    const params = useParams();
    const pathParam = params["*"];

    // Add the leading '/' back on
    const path = '/' + pathParam;

    // Query AEM for the Adventures's details, using the Content Fragment's `path`
    const { adventure, references, error } = useAdventureByPath(path);

    // Handle error and loading conditions
    if (error) {
        return <Error errorMessage={error} />;
    } else if (!adventure) {
        return <Loading />;
    }

    return (<div className="adventure-detail">
        ...
        <AdventureDetailRender {...adventure} references={references} />
    </div>);
}
...
recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4