سؤال

أواجه مشكلة.

لقد قمت بتنفيذ phaselistener ، والذي يهدف إلى إضافة فئة نمط إلى أي مكونات UIInput في الشجرة التي تحتوي على رسائل متصلة بها ، وتزيل فئة النمط إذا لم يكن لديها أي رسائل مرتبطة بها.

يعمل Phaselistener في مرحلة Render_response ، ويقوم بعمله في كل من أساليب قبل الضعف وما بعده أثناء تصحيح الأخطاء. أثناء تصحيح الأخطاء ، وجدت أنه قبل أن لا يمكنه الوصول إلى شجرة المكونات الكاملة ، ولكن بعد الطور. أي تغييرات تم إجراؤها في مرحلة ما بعدها لا يتم تقديمها.

كيف يمكنني القيام بهذا؟ أريد أن يكون هذا جانب الخادم بالكامل.

شكرًا،

جوامع

هل كانت مفيدة؟

المحلول 2

تم تنفيذه باستخدام عرض عرض ، ومع ذلك فهو غير فعال. لا يمكن لـ Phaselistener في مرحلة الاستجابة للعرض الوصول إلى شجرة المكون.

نصائح أخرى

تتوفر شجرة مكون JSF فقط بعد وقت بناء العرض. ال RENDER_RESPONSE المرحلة ليست بالضرورة لحظة جيدة للوصول إلى شجرة مكون JSF الكاملة قبل تقديمها. خلال طلب أولي احصل دون أي <f:viewAction>, ، شجرة المكونات الكاملة متوفرة فقط في afterPhase لأنه يتم بناؤه خلال RENDER_RESPONSE. أثناء Postback ، تتوفر شجرة المكونات الكاملة في 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() على النحو التالي وجمع جميع معرفات العميل لمكونات الإدخال غير الصالحة (هذا 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 omnifaces لديه <o:highlight> المكون الذي يفعل هذا بالضبط.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top