View-model overlays
A view-model overlay is a mechanism for adding data to a view. Brightspot "overlays" the additional data on top of the views' data produced by the view models. The data may be related to the underlying model producing the view, or it could be used to provide common data across all views. For example, you can easily add a permalink to all of your project's pages with a view-model overlay. This feature also saves you the effort of possibly extending existing models or creating a new class hierarchy to add the object to many view models.
Direct view model overlay value
You can directly add a specific view model overlay key's value to every view. The following example describes how to create a view model overlay that inserts a permalink into each view. This example works best if you define a default URL for the site as described in Settings for the Global site or Creating sites.
Step 1: Create model
You can use any new or existing model with an overlay. No extra coding is required. For an example of a simple model, the snippet Simple content type with text and image fields.
Step 2: Create view model overlay
package content.article; import com.psddev.cms.view.ViewModelOverlay; import com.psddev.dari.db.State; import com.psddev.dari.util.CompactMap; import java.util.Map; import java.util.function.Supplier; import com.psddev.cms.db.Directory; public class PermalinkViewModelOverlay implements ViewModelOverlay { 1 @Override public Map<String, Supplier<Object>> create(Object model, String viewTemplate) { Map<String, Supplier<Object>> overlay = new CompactMap<>(); 2 overlay.put("fullPermalink",() -> State.getInstance(model).as(Directory.ObjectModification.class).getFullPermalink()); 3 return overlay; } }
Declares a class that implements | |
Creates a map of key-value pairs. | |
Retrieves the current page's permalink, and assigns it to the key |
Step 3: Create data file
You can use any new or existing Styleguide JSON data file. No extra coding is required. For an example of a simple data file, see the snippet Sample data file.
Step 4: Insert overlay key Into template
Referring to the snippet Creating a view model overlay, you now have access to the key fullPermalink
in every view by inserting that key as a placeholder in a Handlebars template. When rendering the view, Brightspot retrieves the value for the placeholder without your implementing a method in any view model.
<html> <body> <div class="Article"> <div class="Article-headline"> <h1>{{headline}}</h1> </div> <div class="Article-body"> {{body}} </div> <div class="Article-body"> Permalink to this item: {{fullPermalink}} </div> </div> </body> </html>
In the previous snippet, the placeholder {{fullPermalink}}
is the key contained in the overlay.
Indirect view model overlay value
You may need to overlay a view on a given view's value. To do this, you create a view model overlay that returns an object for a particular key. When the view model overlay adds the object to the view model, it converts the object to a view using the view system to find an appropriate view model. The view model for this particular object must be marked with the ViewModelOverlayValueEntryView
interface to indicate to the view system the appropriate view to use for the object in the context of the view model overlay.
The following example describes how to use a view model overlay to add a footer to an existing view for articles. The example assumes you already have a working parent model, view, and view model into which you want to insert the overlay's view. For an example of creating a simple model, view, and view model for an article, see the Tutorial.
Step 1: Create child model
Create a model Footer.java
for the footer.
import com.psddev.cms.db.Content; import com.psddev.dari.util.StorageItem; public class Footer extends Content { private StorageItem imageFile; private String caption; /* Getters and setters */ }
Step 2: Create child template
Create a template Footer.hbs
for the footer. The overlay injects this template as it renders the parent view.
<div class="Footer"> <p class="Footer-p">{{caption}}</p> <p class="Footer-p"><img src="{{imagefile}}"/></p> </div>
Step 3: Create child data file
In the same directory as Footer.hbs
, create the corresponding data file Footer.json
.
{ "_template": "Footer.hbs", "caption": "{{words(4)}}", "imagefile": "{{image(100, 100)}}" }
Step 4: Create view model overlay
Declare a view model overlay class FooterViewModelOverlay
, and insert an instance of the footer's model into the overlay.
import com.psddev.cms.view.ViewModelOverlay; import com.psddev.dari.util.CompactMap; import com.psddev.dari.util.UrlStorageItem; public class FooterViewModelOverlay implements ViewModelOverlay { 1 @Override public Map<String, Supplier<Object>> create(Object model, String viewTemplate) { if (model instanceof Footer) { 2 return null; } Map<String, Supplier<Object>> overlay = new CompactMap<>(); 3 Footer footer = new Footer(); 4 UrlStorageItem file = new UrlStorageItem(); file.setPath("http://cdn.perfectsense.psdweb.psdops.com/6d/5d/efd1da434d6abd8b1b08b8b29c4c/brightspot-logo-183.png"); footer.setImageFile(file); footer.setCaption("This web site delivered by:"); overlay.put("footer", () -> footer); 5 return overlay; } }
Declares a class that implements | |
Tests if the current model is a | |
Instantiates an overlay map. | |
Instantiates the child model and set its properties. | |
Adds the model to the overlay map using the key |
Step 5: Create child view model
In the same directory as Footer.java
, create a view model FooterViewModel.java
.
package content.article; import com.psddev.cms.view.ViewModel; import com.psddev.cms.view.ViewModelOverlayValueEntryView; import styleguide.content.article.FooterView; public class FooterViewModel extends ViewModel<Footer> implements FooterView, ViewModelOverlayValueEntryView { 1 @Override public CharSequence getImagefile() { return model.getImageFile().getPublicUrl(); } @Override public CharSequence getCaption() { return model.getCaption(); } }
Step 6: Add overlay key to parent template
Open the template for which you want to include the overlay, and use the overlay key used in Step 4.
<html> <body> <div class="Article"> <div class="Article-headline"> <h1>{{headline}}</h1> </div> <div class="Article-body"> {{body}} </div> <div> {{footer}} 1 </div> </div> </body> </html>