SPA AEM : How can we apply business logic in .model.json output ?

navjots90210021

05-03-2020

Requirement is to show components of Page-A to specific user group therefore we need to apply business logic where model.json is getting generated ? Any pointers on how to do this ?

Currently when /content/xyz/en.model.json is generated, it checks components on each page and call the sling model for those component. Before calling, i want to check some user info and then call the sling model else skip it.

 

Accepted Solutions (1)

Accepted Solutions (1)

navjots90210021

06-03-2020

The root .model.json is getting rendered by ComponentExporter. This is different than normal jackson exporter. So, the business logic can go into

getExportedType() that is in each sling model. if we return NULL from here instead of resource type, the component do not renders on Front End.
This would require un-caching of root .model.json if some properties needs to be checked on each request.

 

I am looking now versioning of this root .model.json and use selector in order to cache .model.json with different names for diff req types. I am unable to actually get how root .model.json is invoking sling models. If I use different selector in sling model say 'selector1', still the model gets called with '.model' selector.
Update : Versioning can be achieved with .model.group1.json, Aapache can read some cookie, redirect request of .model.json to  .model.group1.json, and the sling model will have request selectors .model.group1.

Thanks @Briankasingli  for looking into this. 

Answers (1)

Answers (1)

Briankasingli

MVP

05-03-2020

@navjots90210021,

Apache Sling Models currently includes a single exporter, using the Jackson framework, which is capable of serializing models as JSON. Adobe's new core components are built with Sling Models, meaning that if you can easily build a headless AEM solution only using the core components. If you are using Adobe's core page component, and editable templates, you can replace ".html" with ".model.json", and you will get a JSON representation of the page structure (resourceType & all used components); assuming that you're Apache Dispatcher module rules allow you to access .model.json. e.g: https://example.com/home.model.json

Then there's no magic happening with the Jackson Exporter; all getter properties of your Sling Models class will exposed, and serialized to JSON. This means that if you run some kind of logic in your @PostConstruct method, then set the property, the computed value will be exposed in your JSON.

Take the example below:

 

 

 

 

@Model(adaptables = Resource.class,
        resourceType = ComponentExample.RESOURCE_TYPE,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ComponentExample {

    protected static final String RESOURCE_TYPE = "my-site/components/content/componentexample";

    @ScriptVariable
    private Page currentPage;

    private String pagePath;

    private String logicTitle;

    @PostConstruct
    public void init() {
        if (YOUR_CONDITIONAL_LOGIC_GOES_HERE) {
            pagePath = currentPage.getPath();
            setLogicTitle();
        }
    }

    private void setLogicTitle() {
        // logic goes here
        logicTitle = "results";
    }

    public String getPagePath() {
        return pagePath;
    }

    public String getLogicTitle() {
        return logicTitle;
    }
}

 

 

 

 

When you append ".model.json" to your page (created with Adobe core components), if you have this component exist on the page && if YOUR_CONDITIONAL_LOGIC_GOES_HERE == true, then you will see the JSON response is:

 

{
    pagePath: 'path of page',
    logicTitle: results',
}

 

 

I can't stress to always add unit tests with your Sling Models. A great example that I like to share is this example - https://sourcedcode.com/aem-sling-models-unit-test-junit-4-with-examples

I hope this helps,

Brian.

 

Thanks for your reply.

I am using SPA framework with React, and if the component is not available in .model.json then, react does not even render that component.

So, what you suggested is applicable if I want to expose different json values based upon business requirement. But my scenario is to HIDE  Component-X in .model.json and therefore UI will not show it. I even tried to return from PostContruct so that the sling model does not export anything, but  it still export all get functions. Is there any way we can deny sling jackson exporter based upon some condition in postConstruct or somewhere ?

@Briankasingli 

 

The comment 2 I added works fine, but looks like it might require some workflow to be created that can crawk in jcr content node and then add the cug policy. This would be my last option.

I would still do it in the sling model. In your sling model, you can add logic to detect if you are in author mode. if author mode, always show. 

@ScriptVariable 
private SightlyWCMMode wcmmode;

wcmmode.isEdit();
You also need to watch out for this; only because you will add too much load to your publish instance. Caching should be your first priority. How will you cache your JSON response?

Sling model exporter will export all keys, I think the only thing we can control is values for those keys. I thing you meant this ? This would require additional check in UI in order to render the component. But if the sling model itself does not export anything, then UI will not render the component. Is there any way we can make sling model do not export anything based upon if condition ?

 

Its B2B and traffic would be very low, so no caching of model.json as of now.

 

Earlier though of versioning of model json based upon CUG groups but that does not work as we can change one selector i.e change model.json to group1.json; but can not add multiple selectors.My initial though was use groups as selector and cache the json. Also sling models will look for this selector and generate the content.

Sure, you are asking "How to Dynamically Deserialize JSON In Java With Jackson". Check it out here - https://nickolasfisher.com/blog/How-to-Dynamically-Deserialize-JSON-In-Java-With-Jackson

Not exactly. Let's say home page has 3 components, https://example.com/home.model.json --> This will export the data from 3 sling models. What I am looking is export data from only 2 components instead of 3 based upon some if condition, else export from 3 components.

If I get into this, just by not caching .model.json will fulfill the purpose.

My last try would be to edit your basePage template.

Create your own Sling Model version of the Page Sling Model, and add logic to exclude objects based on conditions from the returned List object:

 

com.adobe.cq.wcm.core.components.models.Page

 

 

But the spa project uses spa core component at "com.adobe.aem.spa.project.core.models.Page". This is not public, so can not even get the file and over-ride it.