Hello,
I am facing issue in AEM SPA shorten url page ui rendering.
So, my setup is as below,
1. I have template structure depth set to 0 which will trigger a network call to root json i.e. en.model.json and then respective page.model.json
2. I added sling mapping under /etc/map which seems to be working fine. My sling mapping properties are
sling:match = localhost.4503/us
sling:internalRedirect = /content/site-name/us
Now, page.html call and other model.json call is success if I hit the url "http://localhost:4503/us/test.html" and all react clientlibs loads as well in network tab.
Can you please help what am I doing wrong here and what can be done to work this?
Thanks.
@kautuk_sahniif you help tag AEM SPA experts here. It will help.
Solved! Go to Solution.
Views
Replies
Total Likes
This issue fixed with one change.
On spa root template page policy, we need to uncheck isRoot checkbox under Hierarchical Structure. Then, it will not send a extra rootpage.model.json call to AEM and only a single call requestedpage.model.json to render page content and page will load.
It appears that your setup is generally correct, but let's check a few things:
Ensure Sling Mappings are Active:
Check Content Structure:
Dispatcher Configuration:
JSON Responses:
Network Calls:
yes @partyush
All things which you mentioned is in place.
I am not using dispatcher, so testing directly on local publish instance.
One thing to notice here is,
1. I have template structure depth set to 0 which will trigger a network call to root json i.e. en.model.json and then respective page.model.json
Will this cause any issue in rendering UI for SPA?
Hi @iamnjain
Verify that the generated JSON structure aligns with the expectations of your SPA. Confirm that it includes the necessary data for rendering your SPA components.
And also
Ensure that your SPA components are coded to handle the asynchronous loading of data from both the root JSON and subsequent page JSONs. Make certain that your JavaScript logic waits for the required data before attempting to render UI components.
Hi @iamnjain,
If I good understand you are trying to short urls in SPA in the same way you would do that using HTL, right?
If so, then this will not work, this is one of the limitations of SPA, you can find all the limitations under https://experienceleague.adobe.com/docs/experience-manager-cloud-service/content/implementing/develo...
Nevertheless, that does not mean you can't have short links, but in that case you will have to use resourceResolver.map method explicitly, on each property in your sling model that contains url you would like to be short. It will then be exported in short form in your model.json
Hi @lukasz-m
Thanks for your response.
So I understand the limitations.
The page I am testing doesn't have any Links, only a text component which is not rendering with shorten URL and render fine with long URL.
How it will work, if you can help. I explained the scenario above.
If you have link inside text component this will be a bit more difficult, you will have to:
Of course you will still need a sling mapping, because it will be used by map method from resourceResolver to create short url.
Here is a sample code of Sling model that extends Text core component to create short url inside text:
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Via;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.via.ResourceSuperType;
import com.adobe.cq.wcm.core.components.models.Text;
import java.util.Optional;
import java.util.regex.Pattern;
@Model(
adaptables = SlingHttpServletRequest.class,
adapters = { TextModel.class, ComponentExporter.class },
resourceType = TextModel.RESOURCE_TYPE,
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
@Exporter(
name = ExporterConstants.SLING_MODEL_EXPORTER_NAME,
extensions = ExporterConstants.SLING_MODEL_EXTENSION
)
public class TextModel implements Text {
private static final Pattern HREF_PATTERN = Pattern.compile("(?i)\\bhref\\s*=\\s*[\"'](\\S+)[\"']");
static final String RESOURCE_TYPE = "smaple/components/text";
@Self
private SlingHttpServletRequest request;
@Self
@Via(type = ResourceSuperType.class)
protected Text delegate;
@Override
public String getText() {
return Optional.ofNullable(delegate.getText())
.map(this::mapLinks)
.orElse(null);
}
@Override
public String getExportedType() {
return RESOURCE_TYPE;
}
private String mapLinks(String text) {
var matcher = HREF_PATTERN.matcher(text);
var output = new StringBuilder();
while (matcher.find()) {
var hrefValue = matcher.group(1);
var mappedHrefValue = map(request, hrefValue);
matcher.appendReplacement(output, "href=\"" + mappedHrefValue + "\"");
}
matcher.appendTail(output);
return output.toString();
}
private String map(SlingHttpServletRequest request, String path) {
ResourceResolver resourceResolver = request.getResourceResolver();
return (request != null) ? resourceResolver.map(request, path) : resourceResolver.map(path);
}
}
Hi @lukasz-m
This example is specific to a component and model. But I think I need to extend core Page model to tweak the logic of url shortening and content will start rendering.
Can you please help on that if you have any example?
@iamnjain We did resolve urls shortening long back on the react-spa with custom changes. If may I remember correctly you have url short all the :path params in the model.json. So Adobe spa module checks if the url of page in browser(request uri) matches the :path in the model.json then there will be rendering of page with all the details. If it is not, spa page will have no content.
Reference issues:
Can you please add code snapshot for the same which you modified?
Did you extended any OOTB Sling models for this?
This will help me. Thanks.
Sorry, as I do not have access to the code now will not be able to provide the code snippet. If I remember it correctly, I created a spa project out of We-Retail Journal project: https://github.com/adobe/aem-sample-we-retail-journal and have to short url at these methods getExportedPath(), getModelUrl() and getChildPageModels() in hierarchy page model classes. Remember to have :path should match the request url to render anything on spa.
@iamnjain Did you find the suggestions from users helpful? Please let us know if more information is required. Otherwise, please mark the answer as correct for posterity. If you have found out solution yourself, please share it with the community.
Views
Replies
Total Likes
The original problem is that the AEM SPA is triggering unnecessary network calls to the root JSON (en.model.json) and the respective page.model.json for every component rendering. This is because the template structure depth is set to 0, which tells the AEM SPA to load all of the child components of a page in one go. This is causing performance issues and preventing the content from rendering correctly.
To solve this problem, you need to extend the core Page model to tweak the logic of URL shortening. This will allow you to control how the URLs are generated and avoid unnecessary network calls.
Here's how to extend the core Page model to solve the problem:
Create a custom Page model class. This class should extend the com.adobe.aem.spa.project.core.models.Page
class.
Override the getRootUrl
method in your custom Page model class. This method is responsible for generating the root URL for the page. In your override, you should check if the template structure depth is 0. If it is, you should return the full URL of the page. Otherwise, you should return the root URL as generated by the default getRootUrl
method.
Inject your custom Page model class into the AEM SPA. This can be done by adding a Sling resource provider for your custom Page model class.
Once you have completed these steps, the AEM SPA will use your custom Page model class to generate the root URLs for pages. This will prevent unnecessary network calls and allow the content to render correctly.
public String getRootUrl() {
if (getTemplateStructureDepth() == 0) {
return getPageModel().getFullUrl();
} else {
return super.getRootUrl();
}
}
OR
Have tried the option of "Exclude Root Levels"?
@iamnjain Did this help?
Views
Replies
Total Likes
No, issue is not fixed yet.
I am unable to find getRootUrl() method to override in com.adobe.aem.spa.project.core.models.Page
This issue fixed with one change.
On spa root template page policy, we need to uncheck isRoot checkbox under Hierarchical Structure. Then, it will not send a extra rootpage.model.json call to AEM and only a single call requestedpage.model.json to render page content and page will load.
When I did isRoot uncheck, then shorten URL starts working on dispatcher, but it lost SPA behaviour.
We need to hard refresh every page when we navigate from one page to another. On click of link, only URL get change, and not that page content. When we refresh page or do hard refresh from React application using window.location.href = url; then it works.
How can we maintain SPA behavior and handle shorten URLs?
Any suggestion would be helpful from AEM SPA experts.
Views
Replies
Total Likes
Hi @iamnjain Did you get a solution for this issue? We are also facing the same issue.
Views
Replies
Total Likes
Views
Likes
Replies