source

검증 오류 발생 후 PrimeFaces AJAX를 사용하여 텍스트필드에 입력하려면 어떻게 해야 하나요?

gigabyte 2023. 2. 28. 23:34
반응형

검증 오류 발생 후 PrimeFaces AJAX를 사용하여 텍스트필드에 입력하려면 어떻게 해야 하나요?

뷰에 자동 완성 및 gmap 현지화를 위한 Ajax 부분 처리를 수행하는 폼이 있습니다.백업 빈은 엔티티 오브젝트 "Address"를 인스턴스화하고 폼 입력이 참조되는 오브젝트를 나타냅니다.

@ManagedBean(name="mybean")
@SessionScoped
public class Mybean implements Serializable {
    private Address address;
    private String fullAddress;
    private String center = "0,0";
    ....

    public mybean() {
        address = new Address();
    }
    ...
   public void handleAddressChange() {
      String c = "";
      c = (address.getAddressLine1() != null) { c += address.getAddressLine1(); }
      c = (address.getAddressLine2() != null) { c += ", " + address.getAddressLine2(); }
      c = (address.getCity() != null) { c += ", " + address.getCity(); }
      c = (address.getState() != null) { c += ", " + address.getState(); }
      fullAddress = c;
      addMessage(new FacesMessage(FacesMessage.SEVERITY_INFO, "Full Address", fullAddress));
      try {
            geocodeAddress(fullAddress);
        } catch (MalformedURLException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XPathExpressionException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void geocodeAddress(String address)
            throws MalformedURLException, UnsupportedEncodingException,
            IOException, ParserConfigurationException, SAXException,
            XPathExpressionException {

        // prepare a URL to the geocoder
        address = Normalizer.normalize(address, Normalizer.Form.NFD);
        address = address.replaceAll("[^\\p{ASCII}]", "");

        URL url = new URL(GEOCODER_REQUEST_PREFIX_FOR_XML + "?address="
                + URLEncoder.encode(address, "UTF-8") + "&sensor=false");

        // prepare an HTTP connection to the geocoder
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        Document geocoderResultDocument = null;

        try {
            // open the connection and get results as InputSource.
            conn.connect();
            InputSource geocoderResultInputSource = new InputSource(conn.getInputStream());

            // read result and parse into XML Document
            geocoderResultDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(geocoderResultInputSource);
        } finally {
            conn.disconnect();
        }

        // prepare XPath
        XPath xpath = XPathFactory.newInstance().newXPath();

        // extract the result
        NodeList resultNodeList = null;

        // c) extract the coordinates of the first result
        resultNodeList = (NodeList) xpath.evaluate(
                "/GeocodeResponse/result[1]/geometry/location/*",
                geocoderResultDocument, XPathConstants.NODESET);
        String lat = "";
        String lng = "";
        for (int i = 0; i < resultNodeList.getLength(); ++i) {
            Node node = resultNodeList.item(i);
            if ("lat".equals(node.getNodeName())) {
                lat = node.getTextContent();
            }
            if ("lng".equals(node.getNodeName())) {
                lng = node.getTextContent();
            }
        }
        center = lat + "," + lng;
    }

자동 완성 및 맵 에이잭스 요청은 제출 시 폼 전체를 처리하기 전에 정상적으로 동작합니다.검증에 실패해도 뷰에서 업데이트할 수 없는 필드 fullAddress를 제외하고 Ajax는 정상적으로 작동합니다.Ajax 요청 후 backing bean에서 fullAddress 값이 올바르게 설정되어 있습니다.

<h:outputLabel for="address1" value="#{label.addressLine1}"/>
<p:inputText required="true" id="address1" 
          value="#{mybean.address.addressLine1}">
  <p:ajax update="latLng,fullAddress" 
          listener="#{mybean.handleAddressChange}" 
          process="@this"/>
</p:inputText>
<p:message for="address1"/>

<h:outputLabel for="address2" value="#{label.addressLine2}"/>
<p:inputText id="address2" 
          value="#{mybean.address.addressLine2}" 
          label="#{label.addressLine2}">
  <f:validateBean disabled="#{true}" />
  <p:ajax update="latLng,fullAddress" 
          listener="#{mybean.handleAddressChange}" 
          process="address1,@this"/>
</p:inputText>
<p:message for="address2"/>

<h:outputLabel for="city" value="#{label.city}"/>
<p:inputText required="true" 
          id="city" value="#{mybean.address.city}" 
          label="#{label.city}">
  <p:ajax update="latLng,fullAddress" 
          listener="#{mybean.handleAddressChange}" 
          process="address1,address2,@this"/>
</p:inputText>
<p:message for="city"/>

<h:outputLabel for="state" value="#{label.state}"/>
<p:autoComplete id="state" value="#{mybean.address.state}" 
          completeMethod="#{mybean.completeState}" 
          selectListener="#{mybean.handleStateSelect}"
          onSelectUpdate="latLng,fullAddress,growl" 
          required="true">
  <p:ajax process="address1,address2,city,@this"/>
</p:autoComplete>
<p:message for="state"/> 

<h:outputLabel for="fullAddress" value="#{label.fullAddress}"/>
<p:inputText id="fullAddress" value="#{mybean.fullAddress}" 
          style="width: 300px;"
          label="#{label.fullAddress}"/>
<p:commandButton value="#{label.locate}" process="@this,fullAddress"
          update="growl,latLng" 
          actionListener="#{mybean.findOnMap}" 
          id="findOnMap"/>

<p:gmap id="latLng" center="#{mybean.center}" zoom="18" 
          type="ROADMAP" 
          style="width:600px;height:400px;margin-bottom:10px;" 
          model="#{mybean.mapModel}" 
          onPointClick="handlePointClick(event);" 
          pointSelectListener="#{mybean.onPointSelect}" 
          onPointSelectUpdate="growl" 
          draggable="true" 
          markerDragListener="#{mybean.onMarkerDrag}" 
          onMarkerDragUpdate="growl" widgetVar="map"/>
<p:commandButton id="register" value="#{label.register}" 
          action="#{mybean.register}" ajax="false"/>

페이지를 새로 고치면 검증 오류 메시지가 사라지고 Ajax가 예상대로 fullAddress 필드를 완료합니다.

또 다른 이상한 동작이 검증 중에 발생합니다.코드와 같이 폼필드의 빈 검증을 무효로 했습니다.다른 검증 오류가 발견될 때까지 정상적으로 동작합니다.그러면 폼을 다시 전송하면 JSF는 이 필드에 대해 bean 검증을 합니다.

검증 상태에서 뭔가 누락된 것 같은데 뭐가 문제인지 알 수가 없어요.JSF 라이프 사이클을 디버깅하는 방법을 아는 사람이 있습니까?좋은 생각 있어요?

문제의 원인은 다음 사항을 고려하여 파악할 수 있습니다.

  • 단계 컴포넌트에 된 값은 "JSF"로됩니다.null유효치는 입력 컴포넌트의 로컬값으로 설정됩니다.

  • 검증 단계에서 특정 입력 컴포넌트에 대한 JSF 검증이 실패하면 제출된 값은 입력 컴포넌트에 저장됩니다.

  • 유효성 검사 단계 후에 하나 이상의 입력 구성요소가 비활성화되면 JSF는 입력 구성요소의 모델 값을 업데이트하지 않습니다.JSF는 응답 단계를 직접 렌더링합니다.

  • 컴포넌트를 때 이 JSF가 합니다.null이 "Nother"가 아닌 표시됩니다. " value가 "NO"로 표시됩니다.null을 사용하다 그렇지 않으면 모델 값이 표시되지 않습니다.

  • 같은 JSF 뷰와 상호 작용하고 있는 한, 같은 컴포넌트 상태를 처리하는 것입니다.

따라서 특정 폼의 전송 검증에 실패하여 다른 Ajax 액션 또는 다른 Ajax 폼(드롭다운 선택이나 모달대화상자 폼의 결과에 따라 필드를 채우는 등)에 의해 입력 필드의 값을 갱신할 필요가 있는 경우는 기본적으로 에서 타겟 입력 컴포넌트를 리셋해야 합니다.호출 작업 중에 편집된 모델 값을 JSF에 표시하도록 하려면 이 명령을 사용합니다.그렇지 않으면 JSF는 검증 실패 시 그대로 로컬 값을 표시하고 비활성화 상태로 유지합니다.

특정의 방법의 1개는, 에 의해서 갱신/재렌더 되는 입력 컴퍼넌트의 모든 ID 를 수동으로 수집해, 그 상태와 값을 에 의해서 수동으로 리셋 하는 것입니다.

FacesContext facesContext = FacesContext.getCurrentInstance();
PartialViewContext partialViewContext = facesContext.getPartialViewContext();
Collection<String> renderIds = partialViewContext.getRenderIds();

for (String renderId : renderIds) {
    UIComponent component = viewRoot.findComponent(renderId);
    EditableValueHolder input = (EditableValueHolder) component;
    input.resetValue();
}

에서도 할 수 요.handleAddressChange()리스너 메서드 또는 콜하고 있는 입력 컴포넌트에 대해 접속한 재사용 가능한 실장 내handleAddressChange()리스너 방식


구체적으로는 JSF2의 사양에 대한 과실이라고 생각합니다.JSF 규격이 다음을 요구한다면, JSF 개발자들에게는 훨씬 더 의미가 있을 것입니다.

  • JSF가 Ajax 요구에 의해 입력 컴포넌트를 갱신/재렌더 할 필요가 있고, 그 입력 컴포넌트가 Ajax 요청의 프로세스/실행에 포함되지 않은 경우, JSF는 입력 컴포넌트의 값을 리셋해야 합니다.

이는 JSF 1060호에서 보고되었으며, OmniFaces 라이브러리에 완전하고 재사용 가능한 솔루션이 구현되어 있습니다(소스 코드는 여기, 데모는 여기에 표시).

업데이트 1: 버전 3.4 이후 PrimeFaces는 이 아이디어를 바탕으로 플레이버에 완전하고 재사용 가능한 솔루션을 도입했습니다.

업데이트 2: 버전 4.0 이후는 새로운 부울 속성을 취득했습니다.resetValues태그 추가 없이 이러한 문제를 해결할 수 있습니다.

업데이트 3: JSF 2.2가 도입되었습니다.이러한 아이디어는<p:ajax resetValues>이 솔루션은 이제 표준 JSF API의 일부가 되었습니다.

BalusC의 설명에 따라 다음과 같이 모든 입력값을 클리어하는 재사용 가능한 리스너를 추가할 수도 있습니다.

public class CleanLocalValuesListener implements ActionListener {

@Override
public void processAction(ActionEvent actionEvent) throws AbortProcessingException {
    FacesContext context = FacesContext.getCurrentInstance();
    UIViewRoot viewRoot = context.getViewRoot();
    List<UIComponent> children = viewRoot.getChildren();

    resetInputValues(children);
}

private void resetInputValues(List<UIComponent> children) {
    for (UIComponent component : children) {
        if (component.getChildCount() > 0) {
            resetInputValues(component.getChildren());
        } else {
            if (component instanceof EditableValueHolder) {
                EditableValueHolder input = (EditableValueHolder) component;
                input.resetValue();
            }
        }
    }
  }
}

또한 로컬 값을 정리해야 할 때마다 사용하십시오.

<f:actionListener type="com.cacib.bean.CleanLocalValuesListener"/>

태그 내부<p:ajax/>, 속성을 추가하십시오.resetValues="true"보기를 통해 데이터를 다시 가져오도록 지시하면 문제를 해결할 수 있습니다.

언급URL : https://stackoverflow.com/questions/6642242/how-can-i-populate-a-text-field-using-primefaces-ajax-after-validation-errors-oc

반응형