문제

문제가 있습니다.

나는 메시지가 첨부된 트리의 UIInput 구성 요소에 스타일 클래스를 추가하고 메시지가 첨부되지 않은 경우 스타일 클래스를 제거하기 위한 PhaseListener를 구현했습니다.

PhaseListener는 RENDER_RESPONSE 단계에서 실행되며 디버깅하는 동안 beforePhase 및 afterPhase 메서드 모두에서 작동합니다.디버깅하는 동안 beforePhase는 전체 구성 요소 트리에 액세스할 수 없지만 afterPhase는 액세스할 수 있다는 사실을 발견했습니다.afterPhase에서 수행된 모든 변경 사항은 렌더링되지 않습니다.

이 문제를 어떻게 해결하나요?나는 이것이 완전히 서버 측이기를 원합니다.

감사해요,

제임스

도움이 되었습니까?

해결책 2

ViewHandler를 사용하여 구현되었지만 효율적이지는 않습니다. 렌더 응답 단계의 Phaselistener는 구성 요소 트리에 액세스 할 수 없습니다.

다른 팁

JSF 구성 요소 트리는 뷰 빌드 시간 이후에만 사용할 수 있습니다.그만큼 RENDER_RESPONSE 단계는 렌더링되기 전에 전체 JSF 구성 요소 트리에 액세스할 수 있는 좋은 순간이 아닐 수도 있습니다.초기 GET 요청 중 <f:viewAction>, 전체 구성요소 트리는 다음에서만 사용할 수 있습니다. afterPhase 그 기간 동안 건설되고 있기 때문에 RENDER_RESPONSE.포스트백 중에 전체 구성 요소 트리를 다음에서 사용할 수 있습니다. beforePhase, 그러나 다른 보기로 이동하면 여전히 변경됩니다. ~ 동안 그만큼 RENDER_RESPONSE 단계이므로 모든 수정 사항이 손실됩니다.

뷰 빌드 시간이 정확히 무엇인지 알아보려면 질문으로 이동하세요. 뷰 빌드 시간은 얼마나 되나요?

기본적으로 "렌더링 시간 보기"를 사용하는 것이 아니라 beforePhase ~의 RENDER_RESPONSE 단계.JSF는 이를 연결하는 여러 가지 방법을 제공합니다.

  1. 일부 마스터 템플릿에서는 preRenderView 청취자 <f:view>.

    <f:view ...>
        <f:event type="preRenderView" listener="#{bean.onPreRenderView}" />
        ...
    </f:view>
    
    public void onPreRenderView(ComponentSystemEvent event) {
        UIViewRoot view = (UIViewRoot) event.getSource();
        // The view is the component tree. Just modify it here accordingly.
        // ...
    }        
    
  2. 또는 전역 구현 SystemEventListener ~을 위한 PreRenderViewEvent.

    public class YourPreRenderViewListener implements SystemEventListener {
    
        @Override
        public boolean isListenerForSource(Object source) {
            return source instanceof UIViewRoot;
        }
    
        @Override
        public void processEvent(SystemEvent event) throws AbortProcessingException {
            UIViewRoot view = (UIViewRoot) event.getSource();
            // The view is the component tree. Just modify it here accordingly.
            // ...
        }
    
    }
    

    실행하려면 아래와 같이 등록하세요. faces-config.xml:

    <application>
        <system-event-listener>
            <system-event-listener-class>com.example.YourPreRenderViewListener</system-event-listener-class>
            <system-event-class>javax.faces.event.PreRenderViewEvent</system-event-class>
        </system-event-listener>
    </application>
    
  3. 또는 맞춤 제공 ViewHandler 당신이 일하는 곳은 어디입니까? renderView().

    public class YourViewHandler extends ViewHandlerWrapper {
    
        private ViewHandler wrapped;
    
        public YourViewHandler(ViewHandler wrapped) {
            this.wrapped = wrapped;
        }
    
        @Override
        public void renderView(FacesContext context, UIViewRoot view) {
            // The view is the component tree. Just modify it here accordingly.
            // ...
    
            // Finally call super so JSF can do the rendering job.
            super.renderView(context, view);
        }
    
        @Override
        public ViewHandler getWrapped() {
            return wrapped;
        }
    
    }
    

    실행하려면 아래와 같이 등록하세요. faces-config.xml:

    <application>
        <view-handler>com.example.YourViewHandler</view-handler>
    </application>
    
  4. 아니면 연결해 보세요. ViewDeclarationLanguage#renderView(), 그러나 이는 실제로 구성 요소 트리를 조작하려는 의도가 아니라 뷰를 렌더링하는 방법을 조작하기 위한 것이므로 약간 가장자리에 있습니다.


관련 없음 구체적인 문제에 대해서는 귀하의 질문에 명시된 구체적인 기능 요구 사항에 대한 올바른 솔루션이 아닙니다.

이는 메시지가 첨부된 트리의 UIInput 구성 요소에 스타일 클래스를 추가하고 메시지가 첨부되지 않은 경우 스타일 클래스를 제거하기 위한 것입니다.

구성 요소 트리를 조작하는 것(결국 JSF 구성 요소 상태가 됨)보다 클라이언트 측 솔루션으로 향하는 것이 더 좋습니다.다음과 같은 반복 구성 요소의 입력 사례를 상상해보십시오. <ui:repeat><h:inputText>.트리에는 물리적으로 입력 구성 요소가 여러 개가 아닌 단 하나뿐입니다!다음을 통해 스타일 클래스 조작 UIInput#setStyleClass() 모든 반복 라운드에서 제시됩니다.

다음을 사용하여 구성 요소 트리를 방문하는 것이 가장 좋습니다. UIViewRoot#visitTree() 아래와 같이 유효하지 않은 입력 구성요소의 모든 클라이언트 ID를 수집합니다(이것은 visitTree() 접근 방식은 반복 구성 요소를 투명하게 고려합니다):

Set<String> invalidInputClientIds = new HashSet<>();
view.visitTree(VisitContext.createVisitContext(context, null, EnumSet.of(VisitHint.SKIP_UNRENDERED)), new VisitCallback() {

    @Override
    public VisitResult visit(VisitContext context, UIComponent component) {
        if (component instanceof UIInput) {
            UIInput input = (UIInput) component;

            if (!input.isValid()) {
                invalidInputClientIds.add(input.getClientId(context.getFacesContext()));
            }
        }

        return VisitResult.ACCEPT;
    }
});

그리고 그 이후에는 패스 invalidInputClientIds JSON 배열을 JavaScript로 변환한 다음 다음을 통해 가져옵니다. document.getElementById() 그리고 변경 className 기인하다.

for (var i = 0; i < invalidInputClientIds.length; i++) {
    var invalidInput = document.getElementById(invalidInputClientIds[i]);
    invalidInput.className += ' error';
}

JSF 유틸리티 라이브러리 옴니페이스 가지고있다 <o:highlight> 정확히 이 작업을 수행하는 구성 요소입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top