Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

Coral UI select multiple field can't remove all value

Avatar

Level 4

Hi Friends,

I am using selected multiple field. But it have problem, when I remove all values that I selected and save it. It can't save with none value selected.

Example: I selected one value and save ok.

select-multiple-field.PNG

after that I go to "Views properties" to edit that field and remove selected value.

select-multiple-field-2.PNG

When I save it comeback again.

select-multiple-field.PNG

If I selected more than one options and save. After that I remove some option and keep one or more than one selected and save, it work fine. If I remove all options and save it, It come back the option before I remove.

Example: I select 2 options and save ok.

select-multiple-field-3.PNG

I remove one option and save it work fine.

select-multiple-field.PNG

If I select 2 options and remove all and save, it back to.

select-multiple-field-3.PNG

 

My code to bind data into select field and check option fields as below.

 

The Json data as below: http://localhost:4502/.abcbenefits.json/

[{"id":"1","description":"asdf à","langCode":"en"},{"id":"2","description":"asdf ádf","langCode":"en"},{"id":"3","description":"adsf sadf","langCode":"en"}]

 

<script>

$(document).ready(function(){

 

 

        var host_url = window.location.protocol + "//" + window.location.host + "/.abcbenefits.json/";

        var benefitSelectedValue = abcbenefits.values;

 

 

        // load property check on edit page or created page.

        var pageNameID = document.getElementById("cq-sites-properties-form");

 

 

// is create page

if(pageNameID === null) {

//loadServiceDataFromURL(host_url);

        }

// is edit page

        else {

        benefitSelectedValue = abcbenefits.values;

loadServiceDataFromURL(host_url);

        }

 

 

        function loadServiceDataFromURL(host_url) {

$.ajax(host_url, {

dataType: "json",

                contentType: "application/json",

                async: false,

                success: function(rawData, status, xhr) {

try {

                        benefitBindData(rawData);

                    } catch (err) {

console.log(err);

                    }

                },

                error: function (xhr, status, err) {

console.log(err);

                }

            });

        }

 

 

function benefitBindData(data) {

$("#abcbenefits> coral-select-item").remove();

var x = document.getElementById("abcbenefits");

var selectedItem = [];

 

 

data.forEach(function(item) {

var option = document.createElement("coral-select-item");

option.innerHTML = item["description"];

option.value = item["id"];

 

 

x.appendChild(option);

if (isSelectedBenefit(item["id"], benefitSelectedValue)) {

//option.selected = true;

selectedItem.push(option); //push selected item into an array

}

});

 

 

setTimeout(function(_selectedItems){

_selectedItems.forEach(function(option) {

option.selected = true;

});

}, 100, selectedItem)

 

 

}

 

 

function isSelectedBenefit(benefitId, benefitSelectedValues){

for(var i = 0; i < benefitSelectedValues.length;i++){

if(benefitId == benefitSelectedValues[i]) return true;

}

return false;

}

 

 

});

</script>

 

Please help me,

Thank you so much,

1 Accepted Solution

Avatar

Correct answer by
Level 4

I created a custom field for select and change the render.jsp file of the custom select field. So, I coded a JavaScript function to check the onchange of the select field. It work fine.

 

%><coral-select id = "abcProperty" <%= attrs.build() %>><%

    if (cfg.get("emptyOption", false)) {

        String value = "";

 

 

        AttrBuilder opAttrs = new AttrBuilder(null, xssAPI);

        opAttrs.add("value", value);

        opAttrs.addSelected(cmp.getValue().isSelected(value, false));

       

        out.println("<coral-select-item " + opAttrs.build() + "></coral-select-item>");

    }

 

 

    for (Iterator<Resource> items = itemIterator; items.hasNext();) {

        printOption(out, items.next(), cmp);

    }

%></coral-select><%!

 

<script>

abcProperty._onSelectionChange = function(){

        setTimeout(function(){

            var coralTaglist = $("#abcProperty> [name='./propertiesBenefits']")

            if(abcProperty._oldSelection.length == 0){

                coralTaglist.append("<input id = \"hiddenProperty\" handle=\"input\" type=\"hidden\" name=\"./propertiesBenefits\" value=\"\">");

coralTaglist[0].hidden = true;

            }

            else{

coralTaglist[0].hidden = false;

            }

        }, 100);

 

 

 

 

};

 

 

</script>

View solution in original post

18 Replies

Avatar

Community Advisor

Hi,

I would suggest you to first try to populate dropdown using datasource instead of DOM manipulation.

Adobe Experience Manager Help | Using Granite DataSource objects to populate AEM Touch UI objects

Thanks
Arun



Arun Patidar

Avatar

Level 4

I used the datasoure but it have that bug. This is my datasource.

<%@page session="false" import="
  org.apache.sling.api.resource.Resource,
  org.apache.sling.api.resource.ResourceUtil,
  org.apache.sling.api.resource.ValueMap,
  org.apache.sling.api.resource.ResourceResolver,
  org.apache.sling.api.resource.ResourceMetadata,
  org.apache.sling.api.wrappers.ValueMapDecorator,
  java.util.List,
  java.util.ArrayList,
  java.util.HashMap,
  java.util.Locale,
  com.adobe.granite.ui.components.ds.DataSource,
  com.adobe.granite.ui.components.ds.EmptyDataSource,
  com.adobe.granite.ui.components.ds.SimpleDataSource,
  com.adobe.granite.ui.components.ds.ValueMapResource,
  com.day.cq.wcm.api.Page,
  com.day.cq.wcm.api.PageManager,
  com.abc.my.core.dto.PropertyAdminDto"%><%
%><%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %><%
%><cq:defineObjects/><%

   // set fallback
   request.setAttribute(DataSource.class.getName(), EmptyDataSource.instance());
  ResourceResolver resolver = resource.getResourceResolver();

   // Create an ArrayList to hold data
   List<Resource> resourceList = new ArrayList<Resource>();

  ValueMap vm = null;

  com.abc.my.core.models.datasource.PropertiesDataSource propertiesDataSource = new com.abc.my.core.models.datasource.PropertiesDataSource();

  ArrayList<PropertyAdminDto> propertyList = propertiesDataSource.getData(resolver, request);

  for (int i = 0; i < propertyList.size(); i++) {
   // allocate memory to the Map instance
   vm = new ValueMapDecorator(new HashMap<String, Object>());

   // Specify the value and text values
   String value = propertyList.get(i).getPropertyId();
  String text = propertyList.get(i).getPropertyName();

   // populate the map
   vm.put("value", value);
  vm.put("text", text);
  resourceList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm));
  }

   //Create a DataSource that is used to populate the drop-down control
   DataSource ds = new SimpleDataSource(resourceList.iterator());
  request.setAttribute(DataSource.class.getName(), ds);

%>

core\models\datasource\BenefitsDataSource.java

package com.abc.my.core.models.datasource;

import com.abc.my.core.dto.BenefitsDto;
import com.abc.my.core.dto.BenefitsResponseDto;
import com.abc.my.core.dto.PropertyAdminDto;
import com.abc.my.core.dto.ResponseDto;
import com.abc.my.core.models.HostConfigUtill;
import com.abc.my.core.utility.ApiManagementConfiguration;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

public class BenefitsDataSource {

   private static final String URL = "benefit/get?langCode=";

  public static ArrayList<BenefitsDto> getData(ResourceResolver resourceResolver, HttpServletRequest request) {

  Gson gson = new Gson();
   String responseData = "default";

   //get language code
   String langCode = ((SlingHttpServletRequestWrapper) request).getRequest().getLocale().getLanguage();

   ApiManagementConfiguration serviceHost = HostConfigUtill.getHost(resourceResolver);


  try {

  responseData = Unirest.get(serviceHost.getHost() + URL + langCode).headers(serviceHost.toHeaderMap()).asString().getBody();
   } catch (UnirestException e) {

  e.printStackTrace();
   }

  ResponseDto<BenefitsResponseDto> data = gson.fromJson(responseData, new TypeToken<ResponseDto<BenefitsResponseDto>>() {}.getType());

  return  data.getContent().getBenefitDtos();
   }

}

Avatar

Community Advisor

Hi,

Can you try to create a sling servlet and registered with resourceType and use this resource type in datasource node.

Inside Sling servlet you can make a ajax request to get json and parse that json and convert into ValueMap and add to datasource.

Example :

https://github.com/arunpatidar02/aem63app-repo/blob/master/java/HelloWorldCompDDServlet.java



Arun Patidar

Avatar

Level 10

Hi,

You can use WCMUsePojo class to populate the dropdown.

Check this HELPX article: Adobe Experience Manager Help | Using an WCMUsePojo class to populate an Experience Manager Touch UI...

Thanks,

Ratna Kumar.

Avatar

Level 10

Look at the Article that Ratna pointed you too. You can populate a Select Drop down via the WCMUsePojo class. This works! Manipulating the DOM via JS you showed is not best practice.

Avatar

Level 10

See the following video that shows this working when using WCMUsePojo

Avatar

Level 4

I know, I think that bug by AEM. Because, If I deleted many options and keep one options it work fine. If I remove all options it doesn't work.

Thank you for your help.

Avatar

Level 4

Yes,

Before I put my question into this. I was created datasource, sling servlet to do that. It work fine, but have an error when I delete all options.

This is my servlet.

package com.abc.my.core.servlets;

import com.abc.my.core.dto.BenefitsDto;
import com.abc.my.core.dto.BenefitsResponseDto;
import com.abc.my.core.dto.ResponseDto;
import com.abc.my.core.models.HostConfigUtill;
import com.abc.my.core.utility.ApiManagementConfiguration;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
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.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* Servlet that writes some sample content into the response. It is mounted for
* all resources of a specific Sling resource type. The
* {@link SlingSafeMethodsServlet} shall be used for HTTP methods that are
* idempotent. For write operations use the {@link SlingAllMethodsServlet}.
*/

@Component(service=Servlet.class,
   property={

  Constants.SERVICE_DESCRIPTION + " = Property Benefits Servlet",
   "sling.servlet.methods=" + HttpConstants.METHOD_GET,
   "sling.servlet.selectors=propertybenefits",
   "sling.servlet.resourceTypes="+ "sling/servlet/default",
   "sling.servlet.extensions=" + "json"
   })

public class PropertyBenefitsServlet extends SlingSafeMethodsServlet {

   private static final Gson gson = new Gson();
  private static final String URL = "benefit/get?langCode=";

   @Override
   protected void doGet(SlingHttpServletRequest req, SlingHttpServletResponse resp) throws ServletException, IOException {

  ResourceResolver resourceResolver = req.getResourceResolver();
   ApiManagementConfiguration serviceHost = HostConfigUtill.getHost(resourceResolver);
   String langCode = ((SlingHttpServletRequestWrapper) req).getRequest().getLocale().getLanguage();

   String responseData = "default";
  try {

  responseData = Unirest.get(serviceHost.getHost() + URL + langCode).headers(serviceHost.toHeaderMap()).asString().getBody();
   }catch (Exception e) {

  e.printStackTrace();
   }

  ResponseDto<BenefitsResponseDto> data = gson.fromJson(responseData, new TypeToken<ResponseDto<BenefitsResponseDto>>() {}.getType());

   resp.setContentType("application/json");
   resp.getWriter().write(gson.toJson(data.getContent().getBenefitDtos()));
   }

}

Avatar

Level 10

Your issue is not reproducible. AEM does let you save with no values - see:

Avatar

Level 10

As we stated - replace your datasource with the article that Ratna pointed you too that uses WCMUsePojo!

Avatar

Level 4

When I click on anny position in the Coral UI form. It show an error

VM552:1 Uncaught SyntaxError: Unexpected token s in JSON at position 0

    at JSON.parse (<anonymous>)

    at receiveMessage (clientlibs.js:60)

When I click on clientlibs.js it goto the line code that happen the error as below.

    /**

     * Receive two-part messages from the TemplatePicker dialog.  The "data" part indicates the

     * template picker path should be updated; the "config" part indicates whether or not the

     * dialog should be closed.

     */

    function receiveMessage(event) {

        if (event.origin !== location.origin) {

            return;

        }

        var fromTemplateBrowser = JSON.parse(event.data);

        if (fromTemplateBrowser.sender !== "templatebrowser") {

            return;

        }

        if (fromTemplateBrowser.data) {

            var $sink = $templatePicker.data("sink"),

                path = fromTemplateBrowser.data.path;

            $sink.val(path).change();

        }

        if (fromTemplateBrowser.config) {

            var action = fromTemplateBrowser.config.action;

            if (action === 'close' || action === 'done') {

                $templatePicker.data("modal").hide();

            }

        }

    }

Do you have anny idea for this. This bug have effect to remove all option in multiple select field?

Thank you so much,

BienHV

Avatar

Level 10

Have you tried using the logic in the article - Adobe Experience Manager Help | Using an WCMUsePojo class to populate an Experience Manager Touch UI...

As I showed in the 2nd video - this issue does not appear when using this Java logic.

Avatar

Level 10

YOu may have found a bug. IN your sample - you are using JSON and in mine - we are using a MAP and DataSource which is populating the Select field. As i showed in video - i am not experiencing your reported issue. I can save the dialog with no options.

Avatar

Level 4

I only used DataSource. But the bug still happen. If I remove many options and hole one option it work. If I remove all options it doesn't work. It back to the previous save.

Avatar

Correct answer by
Level 4

I created a custom field for select and change the render.jsp file of the custom select field. So, I coded a JavaScript function to check the onchange of the select field. It work fine.

 

%><coral-select id = "abcProperty" <%= attrs.build() %>><%

    if (cfg.get("emptyOption", false)) {

        String value = "";

 

 

        AttrBuilder opAttrs = new AttrBuilder(null, xssAPI);

        opAttrs.add("value", value);

        opAttrs.addSelected(cmp.getValue().isSelected(value, false));

       

        out.println("<coral-select-item " + opAttrs.build() + "></coral-select-item>");

    }

 

 

    for (Iterator<Resource> items = itemIterator; items.hasNext();) {

        printOption(out, items.next(), cmp);

    }

%></coral-select><%!

 

<script>

abcProperty._onSelectionChange = function(){

        setTimeout(function(){

            var coralTaglist = $("#abcProperty> [name='./propertiesBenefits']")

            if(abcProperty._oldSelection.length == 0){

                coralTaglist.append("<input id = \"hiddenProperty\" handle=\"input\" type=\"hidden\" name=\"./propertiesBenefits\" value=\"\">");

coralTaglist[0].hidden = true;

            }

            else{

coralTaglist[0].hidden = false;

            }

        }, 100);

 

 

 

 

};

 

 

</script>

Avatar

Level 1
Hi bhoang! Thank you for your good problem description and the solution. It work for me.

Avatar

Level 1

Hi bhoang!

 

Thank you for your good problem description and the solution. It worked for me.

I just needed to change two coral-select properties:

 

onchange instead of _onSelectionChange

values instead of _oldSelection

 

I guess it is because of the differences between the Coral UI versions.

Your script with these changes stayed like this:

 

<script>
    benefitProperty.onchange = function(){
        setTimeout(function(){
            var coralTaglist = $("#benefitProperty > [name='./propertiesBenefits']")
            if(benefitProperty.values.length == 0){
                coralTaglist.append("<input id = \"hiddenProperty\" handle=\"input\" type=\"hidden\" name=\"./propertiesBenefits\" value=\"\">");
                coralTaglist[0].hidden = true;
            }
            else{
                coralTaglist[0].hidden = false;
            }
        }, 100);
    };
</script>

 

Thank you again!