Expand my Community achievements bar.

Inject child nodes that were created by eaem-nested="NODE_STORE" in a Sling Model

Avatar

Level 1

Hi guys,

I have a dialog that has a multifield with a complex object type identified by the snippet below:

<foo

    jcr:primaryType="nt:unstructured"

    sling:resourceType="granite/ui/components/foundation/form/multifield"

    fieldLabel="Foo">

    <field

        jcr:primaryType="nt:unstructured"

        sling:resourceType="granite/ui/components/foundation/form/fieldset"

        eaem-nested="NODE_STORE"

        name="./foo">

        <layout

            jcr:primaryType="nt:unstructured"

            sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"

            method="absolute"/>

        <items jcr:primaryType="nt:unstructured">

            <column

                jcr:primaryType="nt:unstructured"

                sling:resourceType="granite/ui/components/foundation/container">

                <items jcr:primaryType="nt:unstructured">

                    <bar1

                        jcr:primaryType="nt:unstructured"

                        sling:resourceType="granite/ui/components/foundation/form/textfield"

                        fieldLabel="Bar1"

                        name="./bar1"/>                   

                    <bar2

                        jcr:primaryType="nt:unstructured"

                        sling:resourceType="granite/ui/components/foundation/form/textfield"

                        fieldLabel="Bar2"

                        name="./bar2"/>

                    <bar3

                        jcr:primaryType="nt:unstructured"

                        sling:resourceType="granite/ui/components/foundation/form/textfield"

                        fieldLabel="Bar3"

                        name="./bar3"/>

                </items>

            </column>

        </items>

    </field>

</foo>

I've used  eaem-nested="NODE_STORE" to generate a new node per multifield entry in order to keep things organized.

The structure in the repository looks like this:

1237935_pastedImage_4.png

  1237952_pastedImage_6.png

I'm trying to inject this in my Sling Model but without success. I've already tried the examples below but without success.

@Inject

private List<Foo> foo; // Null element

@Inject

private List<Resource> foo; // List with only one element (i.e. foo child node)

@ChildResource

private List<Resource> foo; // List with only one element (i.e. foo child node)

Any ideas on how to inject this type of structures properly?

Thanks!

Diogo

6 Replies

Avatar

Community Advisor

Hi diogo

   If my understanding is correct, you are trying to fetch the foo node ? In that case the best solution is to inject it as resource . PLease find below Sample snippet

               Please note that foo should match the node name of your resource. Since I see the node structure is this 1239251_pastedImage_4.png

            I have named the variable as foo.

          Also, if you don't expect this node to be present always , just add @optional annotation after @inject

I assume this is what you are looking for Sightly + Sling Models Amazing Combination – Rahul Mengji

Thanks

Veena

Avatar

Employee

Can you share the node-structure that you have? That might be easier to see what you want.

Avatar

Level 1

Thanks for your answer.

The structure is already there. Which other detail do you need?

Avatar

Level 2

Hi Diogo,

Did you find any solution ? I was trying to do the same but a little bit different. When I am trying to access the page model json, I see just the sling resource type component name and not the exact node values. I tried different ways and when I say <page-name>.model.json, it always returns the nodes that are at first level. Child nodes are not being retrieved. To explain it better see the following JSON response.

"productlist": {

"columnClassNames": "aem-GridColumn aem-GridColumn--default--12",

":type": "demo/components/content/productlist",

"headlineText": "Product List"

}

if you see the above JSON which is rendered when I did page mode json and it has a component called ProductList which is a multifield type. IT returns the type of component and not exact values inside it. I tried all ways using Jackson annotations to make it work, but no luck. So if anyone has faced the same issue and could help me with the best approach, it would be helpful.

When I checked List component, it has one multifield value as text and it is stored as String[] in JCR. I am not sure how can I do that with the composite multifield. Because under productlist node I will be having node structure as below.

Screen Shot 2018-05-01 at 7.02.34 AM.png

Screen Shot 2018-05-01 at 7.02.53 AM.png

Each node having two properties. It could be more. To retrieve the values, I have a sling model with these two properties and I am referencing the same model as List<LinksModel> links where LinksModel is the sling model with above mentioned two properties.

Avatar

Level 1

Hi narendran63116907​,

Not sure if I got exactly all details of your question but I will try to help. As far as I can understand (and please correct me if I'm wrong) you want to access all child nodes of a multifield that has separate child nodes instead of a single node whose properties are kept in String[].
To make sure that you keep the information in separate child nodes you need to add eam-nested="NODE_STORE" to your multifield properties in your cq:dialog.xml file:

<multifield

    jcr:primaryType="nt:unstructured"

    sling:resourceType="granite/ui/components/foundation/form/multifield"

    fieldLabel="Fields">

    <field

        jcr:primaryType="nt:unstructured"

        sling:resourceType="granite/ui/components/foundation/form/fieldset"

        eaem-nested="NODE_STORE"

        name="./fields">

        <layout

            jcr:primaryType="nt:unstructured"

            sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"

            method="absolute"/>

        <items jcr:primaryType="nt:unstructured">

            <column

                jcr:primaryType="nt:unstructured"

                sling:resourceType="granite/ui/components/foundation/container">

                <items jcr:primaryType="nt:unstructured">

                    <propertyone

                        jcr:primaryType="nt:unstructured"

                        sling:resourceType="granite/ui/components/foundation/form/textfield"

                        fieldLabel="Property One"

                        name="./propertyOne"/>

                    <propertytwo

                        jcr:primaryType="nt:unstructured"

                        sling:resourceType="granite/ui/components/foundation/form/textfield"

                        fieldLabel="Property Two"

                        name="./propertyTwo"/>

                </items>

            </column>

        </items>

    </field>

</multifield>

Then you need to create a Sling model, adaptable from Resource, that is able to inject either propertyOne and propertyTwo:

@Model(adaptables = Resource.class)

public class FieldModel {

    @ValueMapValue(injectionStrategy = InjectionStrategy.REQUIRED)

    private String propertyOne;

    @ValueMapValue(injectionStrategy = InjectionStrategy.REQUIRED)

    private String propertyTwo;

}

For your page you need to do a Sling Model (in this case you have to adapt it to your needs as you require a JSON response) and inject your multifield values in form of a list (example below):

@Model(adaptables = Resource.class)

public class PageModel {

    @Inject

    @Default(values = {})

    private List<FieldModel> fields;

}

Hope this helps!

Cheers

Avatar

Level 1

Thanks for your answer.

Actually I was trying to avoid inject the Resource like that because it would imply for me to go and get the child nodes of that resource...which will lead to additional processing.I was looking for a more direct implementation that already provided a List<Foo> or an Foo[] that contained the child nodes.

Let's say that the ideal solution would be to find a way to directly inject the list of foo child in form of List<Foo>