SAP UI5 و Windows للتأكيد: مرة أخرى حول السياق

تحدث المعجزات - أي مبرمج سيقول لك ذلك. (بدلاً من الكتابة)

مساء الخير!

مثال بسيط.

هناك رأي:

<mvc:View 
    controllerName="MyController" 
    xmlns="sap.m" 
    xmlns:core="sap.ui.core" 
    xmlns:mvc="sap.ui.core.mvc">
    <Button text="!" press="handlePress" />
    <Table 
        items="{view>/list/items}" 
        mode="MultiSelect" 
        selectionChange="handleTableSelection">
        <columns>
            <Column>
                <Text text="" />
            </Column>
            <Column>
                <Text text="" />
            </Column>
        </columns>
        <items>
            <ColumnListItem>
                <cells>
                    <ObjectIdentifier title="{view>id}" />
                    <Text text="{view>description}" />
                </cells>
            </ColumnListItem>
        </items>
    </Table>
</mvc:View>

ونفس وحدة تحكم "خداع":

sap.ui.controller("MyController", {
        
    onInit: function () {
        this.__oViewModel = new sap.ui.model.json.JSONModel({
            list: {
                items: [
                    { id: 1, description: 'one' },
                    { id: 2, description: 'two' },
                    { id: 3, description: 'three' }
                ],
                selected: []
            }
        });
        this.getView().setModel(this.__oViewModel, "view");
    },

    handlePress: function (oEvent) {
        sap.m.MessageToast.show(this.__oViewModel.getProperty('/list/selected').join(', '));
    },

    handleTableSelection: function (oEvent) {
        const aSelectedCtx = oEvent.getSource().getSelectedContexts(),
            aSelected = aSelectedCtx.map(o => o.getObject().id);
        this.__oViewModel.setProperty('/list/selected', aSelected);
    }

});

للنظر والتصرف ، سيكون كل هذا متوقعًا تمامًا: من

صورة

خلال النقر على الزر ، ستظهر معرّفات محددة مدرجة بفاصلة (سنترك التحقق من الصفيف غير الفارغ وغيرها من واجهات المستخدم خارج نطاق المقالة).

ولكن تخيل ذلك بالنقر على الزر "هيا بنا!" لا تحتاج فقط إلى عرض معرفات العناصر المحددة ، كما يحدث الآن ، ولكن حذفها من قاعدة البيانات.

مثل هذه الأشياء ، بالطبع ، يجب القيام بها فقط بعد تأكيد إضافي من قبل المستخدم.

حسنًا ، مسألة تافهة - أضف جزء عرض لمربع حوار التأكيد:

ConfirmDialog.fragment.xml

<core:FragmentDefinition
    xmlns='sap.m'
    xmlns:core='sap.ui.core' >
    <Dialog
        id='confirmDialog'
        title=''
        type='Message'
        state='Warning'>
        <content>
            <Label text='  ?' />
        </content>
        <beginButton>
            <Button
                text=''
                press='handleConfirmBtn'/>
        </beginButton>
        <endButton>
            <Button
                text=''
                press='handleCancelBtn'/>
        </endButton>
    </Dialog>
</core:FragmentDefinition>

ووحدة التحكم بها:

ConfirmDialog.controller.js

sap.ui.define([
    "sap/ui/base/ManagedObject"
], function (ManagedObject) {
    "use strict";

    return ManagedObject.extend("project.ConfirmDialog", {

        constructor: function (oView, fnConfirmBtn) {
            this.__oView = oView;
            this.__fnConfirmBtn = fnConfirmBtn;
        },

        exit: function () {
            delete this.__oView;
            delete this.__fnConfirmBtn;
        },

        open: function () {
            const oView = this.__oView;
            let oDialog = oView.byId("confirmDialog");

            if (!oDialog) {
                const oFragmentController = {
                    handleConfirmBtn: () => {
                        this.__fnConfirmBtn();
                        oDialog.close();
                    },
                    handleCancelBtn: () => {
                        oDialog.close();
                    }
                };
                oDialog = sap.ui.xmlfragment(oView.getId(), "project.view.fragment.ConfirmDialog", oFragmentController);
                oView.addDependent(oDialog);
            }
            oDialog.open();
        }

    });
});

كما ترى ، كل شيء كلاسيكي تمامًا ، على مستوى أمثلة SAP UI5 SDK.
الآن ، لاستدعاء مربع الحوار هذا ، نعيد تعريف معالج الزر الرئيسي كما يلي:

handlePress: function (oEvent) {
    const aSelected = this.__oViewModel.getProperty('/list/selected');
    this.__confirmDialog = new ConfirmDialog(this.getView(), () => {
        aSelected.forEach(o => {
            //    
        });
        this.__confirmDialog.exit();
    });
    this.__confirmDialog.open();
}

أي أننا هنا ننشئ حوارنا ، ونمرر كمعلمة طريقة العرض "الرئيسية" التي سيتم تحديد موقعها ، ووظيفة معالج التأكيد.

لقد جئنا هنا إلى الأكثر إثارة للاهتمام.

قبل التقليب ، راجع رمز وحدة تحكم الحوار مرة أخرى.

هل ترى شيئًا غريبًا؟

لا؟

حسنًا ، قم بتشغيل وضع التتبع ، وبعد تحديد أول عنصرين ، لا تتردد في النقر فوق الزر.

        handlePress: function (oEvent) {
            const aSelected = this.__oViewModel.getProperty('/list/selected');  
            // aSelected = [1,2], ,  
            this.__confirmDialog = new ConfirmDialog(this.getView(), () => {
                aSelected.forEach(o => {
                    //   aSelected = [1,2]
                });
                this.__confirmDialog.exit();
            });
            this.__confirmDialog.open();
        }

كل شيء يعمل! يبدو ، ما هو الصيد؟ من الممكن أن يصبح المستخدم لا يشبع ويريد حذف شيء آخر. دعنا نحاول التنبؤ بأفعاله: حدد العنصر الثالث وانقر فوق "Let's Go!":

        handlePress: function (oEvent) {
            const aSelected = this.__oViewModel.getProperty('/list/selected');  
            // aSelected = [3]
            this.__confirmDialog = new ConfirmDialog(this.getView(), () => {
                aSelected.forEach(o => {
                    //   aSelected = [1,2] ???

لماذا [1،2] اسألني. هذا جيد لك ، هناك من تطلبه.

وفي المرة الأولى التي رأيت فيها مثل هذا السلوك القبيح للمترجم ، بدأت أشك في نفسي بصمت. لقد كنت أعمل مع أطر مختلفة منذ فترة طويلة ، لكنني لم أواجه أي شيء مثلها من قبل: من المعروف أن كونست لا يضمن ثبات الأشياء والمصفوفات طوال وجودها - ولكن لم يتم ذكر aSelected في أي مكان آخر. لذلك ظهر ، واستول ، والآن تم تحويله إلى مكالمة هاتفية.

لكنني لن أعذبك لفترة طويلة.

كل شيء عن السياقات والإغلاق الذي يحب جميع المبرمجين شبيبة.

هذا ، في الواقع ، أثناء التنفيذ الأول لـ handleConfirmBtn ، لا يزال لدينا رابط إلى معالجه جنبًا إلى جنب مع السياق بأكمله (بما في ذلك المحدد). ومع التأكيد اللاحق للحذف ، هو ما يسمى.

لم تكن طريقة تصحيح الخطأ بهذه البساطة ولا لبس فيها. لم يكن يكفي فقط نقل إعلان oFragmentController (بعد المكالمة الأولى ، فقد السياق). وكانت الطريقة التالية هي الأكثر إيجازاً (سأعطي كود الطريقة المفتوحة فقط):

open: function () {
    const oView = this.__oView;
    let oDialog = oView.byId("confirmDialog");

    if (!oDialog) {
        const oFragmentController = {
            handleConfirmBtn: function () {
                this.__fnConfirm();
                oDialog.close();
            },
            handleCancelBtn: function () {
                oDialog.close();
            }
        };
        oDialog = sap.ui.xmlfragment(oView.getId(), "project.view.fragment.ConfirmDialog", oFragmentController);
        oDialog.controller = oFragmentController;
        oView.addDependent(oDialog);
    }
    oDialog.controller.__fnConfirm = this.__fnConfirmBtn.bind(this);
    oDialog.open();
}

انتبه إلى آخر 4 أسطر قابلة للتنفيذ: بهذه الطريقة أقوم "بتحريك" المؤشر إلى المعالج الحالي مع السياق الصحيح.

بشكل عام ، كان يجب إضافة سطرين فقط إلى الإصدار الأصلي.

كان من الممكن لقاء واحد
oDialog.setBeginButton(new sap.m.Button({ text: '', press: this.__fnConfirmBtn }));

ولكن هنا ، كما تعلم ، في كل مرة تفتح فيها مربع حوار ، سيتم إنشاء زر جديد ، هذا ليس جيدًا.

فكرت أيضًا في خيار تحديث رد الاتصال عبر oDialog.getBeginButton (). AttachPress ، ولكنه يعلق معالجًا إضافيًا فقط ، كما أن إزالة كل ما هو متاح عبر .detachPress في سطر واحد مثير للاشمئزاز.

هنا خرجت هذه المغامرة من اللون الأزرق تقريبًا (بعيدًا عن الأول ... آه ، ui5!)

PS تمرير وظيفة إلى وظيفة مُنشئ الكائن ، حيث تحتوي إحدى الطرق على كائن تحكم ، والذي يحتوي على إشارات إلى وظائف المعالج. يبدو أن ما يمكن أن يحدث خطأ؟

بشكل عام ، فإن الوضع الموصوف هو سمة من سمات اللغة ، وإطار UI5 ببساطة لا يسمح بحلها بشكل جميل.

All Articles