Expand my Community achievements bar.

How to pass a value from Sling Model to AEM Dialog ?

Avatar

Level 3

I need to pass a value from my Sling Model, for example shopId to my clientlib js associated with the AEM dialog. Following is my clientlib js for aem dialog. 

 

                

touseefk2181136_0-1719114745572.png

 

 

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

16 Replies

Avatar

Level 4

Hi @touseefk2181136 ,

 

You might want to check out this - https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/how-to-use-component-s-dia...

Let me know if you are still facing any issues in fetching the values to JS.

 

Avatar

Level 5

To answer it better, could you please provide details on how your sling Model is getting this shopId which you are trying to retrieve in your dialog js and what are you planning to do with this shopId once it is available in your js? 

Avatar

Level 3

@h_kataria In my sling model, I get shop record from jcr like /content/data/shops by name. Now on the AEM dialog of my component I have fields like shop name, address etc. When user submits (click on Done or OK) AEM dialog I need to post that data to a servlet, I need to include shopId in the payload. In the servlet, I need to check if shop id exists, update the record otherwise create new shop record. Following is my client lib js code which will save shop record. But I tried using hidden field in HTL but AEM dialogue 's html doesn't that hidden field.


(function ($, $document) {
    "use strict";

    $(document).on("foundation-contentloaded", function (e) {
        Coral.commons.ready(function () {
        });
    });


    // When the dialog is submitted
    $(document).on("click", ".cq-dialog-submit", function (e) {

        let dialog = e.currentTarget.closest('coral-dialog');
        let trackingFeature = dialog.getAttribute('trackingfeature');
        if (trackingFeature.includes('shop form')) {


            let shopName = dialog.querySelector('input[name="./shopName"]').value;
            let Addres = dialog.querySelector('input[name="./Addres"]').value


            var shopData = {
                'shopName': shopName,
                'shopId': // I need shopId here,
                'Addres': shopAddress
            };

            $.ajax({
                type: 'POST',
                url: '/bin/test/shopservlet',
                data: shopData,
                success: function (response) {
                    console.log('Data saved successfully: ', response);
                    alert("The shop has been saved successfully")
                },
                error: function (error) {
                    console.error('Error while saving data: ', error);
                    alert("Error while saving data")
                }
            });

        }
    });
})(jQuery, jQuery(document));

Avatar

Level 3

 

@h_kataria Yes shopId is not part of my AEM dialog, it is autogenerated. It is GUID, when we pass data to the shop servlet to save, the shop id is generated if it is not part of the payload  already.  Following is the structure my node
shop.png

Avatar

Level 5

One solution which I can think of is just make an ajax call to your /content/data/shops.infinity.json node in your js, you will get the JSON of your shops data, then you can filter out the node based on the shopName in your current component and get the shopId there itself. 
Hope this helps.

Avatar

Level 3

Hi @touseefk2181136 ,

You may use ajax call /content/data/shops.infinity.json as suggested by @h_kataria  OR you may use below approach.

 

From front-end just pass shopName and shopAddress only in shopData object to Servlet always.

Then in servlet itself first check if that shop name exist by fetching(making http call to /content/data/shops.infinity.json) all shop data then filter to check shop Id present OR you may use queryBuilder to search for shopId with shopName.

If shopId present you can append else generate the shopId

Thanks

 

Avatar

Level 3

Hi @touseefk2181136    PFA,

 

You may easily extract the shop id from path(string operation- split) of search result. Even we can use shopName as well shopAddress to check if present by grouping property in query.

crxdeshop.pngshopid.png

path=/content/data/shop
property=shopName
property.value=name2

 

OR

 

path=/content/data/shop
group.1_property=shopName
group.1_property.value=name2
group.2_property=shopAddress
group.2_property.value=address2
p.limit=-1

 

OR if you want only if shop node has id node as a child or not and  that unique id if present then we can use simple query as below

MukYa1_0-1719146710986.png

 

Avatar

Level 4

Hi @touseefk2181136 

 

After going through the entire thread i guess the best option for you would be to follow the below steps as this is how i tried and worked

  • Create a Sling Model that includes the properties you want to expose. Ensure it's adaptable from the resource and includes the desired value
  • Use the Sling Model to render the value in the component's HTML
  • Write JavaScript to read the value from the HTML and perform any required actions
  • Ensure your JavaScript file is included in your component. You can use the data-sly-call block in your HTL to include the client library

If you are facing any issue in this let me know

Avatar

Level 3

@abhishekanand_ Ok, I am doing this as per your  points

1. Exposed property in sling model

 

@Model(adaptables = Resource.class)
public class ShopModel {

    @Inject
    private String shopId;

    public String getShopId() {
        return shopId;
    }
}

 

2. Render value in html

 

<div data-shop-id="${shopModel.shopId}"></div>

 

3. Write JavaScript to read value. 

 

let shopId = document.querySelector('div[data-shop-id]').getAttribute('data-shop-id');

 


Where I need to write this JavaScript ? If I write this in dialog.js which is my clientlib for AEM dialog then above html data attribute for shop is not available in 'document' object because its scope is coral dialog. 

Kindly explain point 3 and write sample code. 
4. Include the JavaScript File in Your Componen

 

 

<sly data-sly-use.clientLib="/libs/granite/sightly/templates/clientlib.html"
     data-sly-call="${clientLib.js @ categories='clientlib-dialog'}"></sly>

 

Again, after point 2, I am unable proceed document object doesn't have data attribute for shop id.

Thank you.
 

Avatar

Level 4

Hi

 

You can include a js at the component slightly as well, or if you want to keep your js seperate you can do that as well

 

 

<!-- /apps/myproject/components/mycomponent/mycomponent.html -->

<div class="my-component" data-myproperty="${myComponentModel.myProperty @ context='unsafe'}">

</div>

<sly data-sly-call="${'myproject.clientlib.js' @ category='myproject.mycomponent'}"></sly>

 

  • <!-- Inline script to ensure the data attributes are available -->

<script>

    document.addEventListener('DOMContentLoaded', function() {

        var myComponent = document.querySelector('.my-component');

        if (myComponent) {

            var myPropertyValue = myComponent.getAttribute('data-myproperty');

            console.log('The value from the Sling Model is:', myPropertyValue);

 

            // Use myPropertyValue as needed

        }

    });

</script>

Avatar

Level 3

Ok I have done above steps. I am already able to get store id in the above JavaScript code. Now I can see dialog.js clientlib js is loading when the page is loading but first problem is following event not firing. Now even if I move following code in html of the component, event doesn't fire. second problem, still don't know how to pass shop id to dialog.js client lib. If any of these two problems solved, my issue is solved.

 

// When the dialog is submitted
    $(document).on("click", ".cq-dialog-submit", function (e) {

        let dialog = e.currentTarget.closest('coral-dialog');
        let trackingFeature = dialog.getAttribute('trackingfeature');
        if (trackingFeature.includes('shop form')) {


            let shopName = dialog.querySelector('input[name="./shopName"]').value;
            let Addres = dialog.querySelector('input[name="./Addres"]').value


            var shopData = {
                'shopName': shopName,
                'shopId': // I need shopId here,
                'Addres': shopAddress
            };

            $.ajax({
                type: 'POST',
                url: '/bin/test/shopservlet',
                data: shopData,
                success: function (response) {
                    console.log('Data saved successfully: ', response);
                    alert("The shop has been saved successfully")
                },
                error: function (error) {
                    console.error('Error while saving data: ', error);
                    alert("Error while saving data")
                }
            });

 

Will be thankful if you are available for a short call so that I can show you real scenario.

 

Avatar

Level 3

Hi @touseefk2181136 ,

Seems as per you use case below code should work. From frontend just pass shopName and address and made changes in servlet as below.

 

package com.yourproject.core.servlets;//change as per you code base

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.google.gson.Gson;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletPaths;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
import javax.jcr.Session;
import javax.servlet.Servlet;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Component(service = Servlet.class)
@SlingServletPaths(
value = "/bin/test/shopservlet"
)
public class ShopServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ShopServlet.class);
@Reference
private QueryBuilder builder;

@Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) {

try {
String requestBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
JsonObject shopdata = new Gson().fromJson(requestBody, JsonObject.class);
ResourceResolver resolver = request.getResourceResolver();
Session session = resolver.adaptTo(Session.class);
Map<String, String> map = new HashMap<String, String>();

map.put("path", "/content/data/shop");
map.put("property", "shopName");
map.put("property.value", shopdata.get("shopName").getAsString());
map.put("p.limit", "-1");

Query query = builder.createQuery(PredicateGroup.create(map), session);

SearchResult result = query.getResult();
int hits = result.getHits().size();
if (hits > 0) {
String shopId = result.getHits().get(0).getPath().split("/")[4];
//shopId will get appended in shopdata if shopId exist with that shopname else shopdata won't have shopId
shopdata.addProperty("shopId",shopId);
}

//write your existing servlet logic code
//here now shopData will have shopId if exist else it won't have so your existing servlet logic will work


} catch (Exception e) {
log.error(e.getMessage());
}
}

}

However if you insist to use shopid in frontend put below new servlet to you code base and make another ajax call in your js to get shop id and append according before making call to /bin/test/shopservlet

package com.yourproject.core.servlets;//change this as per your code base

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletPaths;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Session;
import javax.servlet.Servlet;
import java.util.HashMap;
import java.util.Map;

@Component(service = Servlet.class)
@SlingServletPaths(
value = "/bin/test/fetchshopid"
)
public class FetchShopIdServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(FetchShopIdServlet.class);
@Reference
private QueryBuilder builder;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {

try {
String shopName = request.getParameter("shopname");
ResourceResolver resolver = request.getResourceResolver();
Session session = resolver.adaptTo(Session.class);
Map<String, String> map = new HashMap<String, String>();

map.put("path", "/content/data/shop");
map.put("property", "shopName");
map.put("property.value", shopName);
map.put("p.limit", "-1");

Query query = builder.createQuery(PredicateGroup.create(map), session);

SearchResult result = query.getResult();
int hits = result.getHits().size();
if (hits > 0) {
String shopId = result.getHits().get(0).getPath().split("/")[4];
response.getWriter().write(shopId);
} else {
response.getWriter().write("null");//or whatever you want to return either 0 or something
}

} catch (Exception e) {
log.error(e.getMessage());
}
}

}

Ajax call endpoint :- http://localhost:6502/bin/test/fetchshopid?shopname=name2
You may pass shopName as query param to check if that shopName exist
Above Servlet will return shopid if exist else will return null string

Thanks

Avatar

Level 3

Hi @touseefk2181136 ,

You can just pass shopName and shopAddress to /bin/test/shopservlet and made changes in servlet as per below code.

 

package com.your-project-path.core.servlets;//your your code base package

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.google.gson.Gson;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletPaths;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
import javax.jcr.Session;
import javax.servlet.Servlet;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Component(service = Servlet.class)
@SlingServletPaths(
value = "/bin/test/shopservlet"
)
public class ShopServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ShopServlet.class);
@Reference
private QueryBuilder builder;

@Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) {

try {
String requestBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
JsonObject shopdata = new Gson().fromJson(requestBody, JsonObject.class);
ResourceResolver resolver = request.getResourceResolver();
Session session = resolver.adaptTo(Session.class);
Map<String, String> map = new HashMap<String, String>();

map.put("path", "/content/data/shop");
map.put("property", "shopName");
map.put("property.value", shopdata.get("shopName").getAsString());
map.put("p.limit", "-1");

Query query = builder.createQuery(PredicateGroup.create(map), session);

SearchResult result = query.getResult();
int hits = result.getHits().size();
if (hits > 0) {
String shopId = result.getHits().get(0).getPath().split("/")[4];
shopdata.addProperty("shopId",shopId);
}

//write your existing servlet logic code here now shopData will have shopId if exist else it won't have so your existing servlet logic will work


} catch (Exception e) {
log.error(e.getMessage());
}
}

}

OR you can use below servlet to get the shopId in js . To get shopId make a call to below servlet
package com.yourproject.core.servlets;

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletPaths;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Session;
import javax.servlet.Servlet;
import java.util.HashMap;
import java.util.Map;

@Component(service = Servlet.class)
@SlingServletPaths(
value = "/bin/test/fetchshopid"
)
public class FetchShopIdServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(FetchShopIdServlet.class);
@Reference
private QueryBuilder builder;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {

try {
String shopName = request.getParameter("shopname");
ResourceResolver resolver = request.getResourceResolver();
Session session = resolver.adaptTo(Session.class);
Map<String, String> map = new HashMap<String, String>();

map.put("path", "/content/data/shop");
map.put("property", "shopName");
map.put("property.value", shopName);
map.put("p.limit", "-1");

Query query = builder.createQuery(PredicateGroup.create(map), session);

SearchResult result = query.getResult();
int hits = result.getHits().size();
if (hits > 0) {
String shopId = result.getHits().get(0).getPath().split("/")[4];
response.getWriter().write(shopId);
} else {
response.getWriter().write("null");//or whatever you want to return either 0 or something
}

} catch (Exception e) {
log.error(e.getMessage());
}
}

}

Make an ajax call from js to get shopId with shopname as query parameter. It will return shopId or null if doesn't exist
Endpoint-
http://localhost:6502/bin/test/fetchshopid?shopname=name2

Avatar

Administrator

@touseefk2181136 Did you find the suggestion helpful? Please let us know if you require more information. Otherwise, please mark the answer as correct for posterity. If you've discovered a solution yourself, we would appreciate it if you could share it with the community. Thank you!  



Kautuk Sahni