मुख्य सामग्री पर जाएँ

Data Grid

यह पृष्ठ अंग्रेज़ी से अनुवादित है। अंग्रेज़ी पृष्ठ पढ़ें

स्थिति: zeyn::DataGrid, zeyn::server के ग्रिड एंडपॉइंट और assets/zeyn/*.js (/_zeyn/zeyn.js के रूप में परोसा गया) द्वारा लागू।

ग्रिड सर्वर पर रेंडर होता है। इसकी पंक्तियाँ उस action से आती हैं जो DataQuery लेती है और Page<E> लौटाती है। ब्राउज़र रनटाइम पृष्ठ माँगता है, उपयोगकर्ता जो करता है (क्रम, फ़िल्टर, लेआउट, संपादन, action) भेजता है और जो HTML लौटता है उसे जगह पर रखता है। हर कॉल सर्वर पर अनुमतियाँ जाँचती है, और क्लाइंट जो भेजे उस पर भरोसा नहीं किया जाता।

DataGrid::of(search_products)
    .mode(DataMode::Server)
    .paging(Paging::pages(25))
    .column(Product::code).width(120).pin_start().filter()
        .link(|p| Window::open(product_editor, ProductParams { id: Some(p.id) }))
    .column(Product::name).flex(1).filter().editable()
    .column(Product::unit).filter().editable().badge(|u| match u {
        Unit::Kg => Tone::Info,
        _ => Tone::Neutral,
    })
    .column(Product::price).filter().editable().avg().max()
    .column(Product::stock).filter().sum().progress(120)
    .column(Product::active).filter().check_icon().editable()
    .edit_with(save_product)
    .row_action(t!("stock.restock"), restock_product, |p| p.id)
    .bulk_action(t!("stock.deactivate"), deactivate_products, Product::id)
    .row_menu(|p| ContextMenu::new()
        .item(t!("stock.edit"), Window::open(product_editor, ProductParams { id: Some(p.id) }))
        .action(t!("stock.restock"), restock_product, p.id))
    .exportable()

कॉलम योग

sum() और avg() पूर्ण संख्याओं और मुद्रा पर काम करते हैं, min() और max() तारीख़ों, समय और क्षणों पर भी, count() हर कॉलम पर। इन्हें किसी अन्य प्रकार पर इस्तेमाल करना कंपाइल नहीं होता। योग हर उस पंक्ति को कवर करते हैं जो फ़िल्टर से मेल खाती है, केवल पृष्ठ को नहीं।

DataQuery::apply मेमोरी के डेटा के लिए इनकी गणना करता है। SQL में पृष्ठांकन करने वाली डेटा परत query.aggregates पढ़ती है और एक एग्रीगेट क्वेरी से Page::with_total(field, op, value) जोड़ती है। ग्रिड केवल वही योग रखता है जो उसके कॉलम घोषित करते हैं, इसलिए क्लाइंट दूसरे नहीं माँग सकता। योग सर्वर पर उपयोगकर्ता की भाषा में स्वरूपित होते हैं। पूर्ण संख्याओं के औसत में दो दशमलव होते हैं (Value::Decimal), और मुद्रा औसत शून्य से दूर की ओर आधे पर पूर्णांकित होकर सबसे छोटी इकाई तक आते हैं।

फ़िल्टर और क्रम

filter() फ़िल्टर पंक्ति में एक फ़िल्टर जोड़ता है, इनपुट कॉलम के प्रकार से चुना जाता है:

कॉलमफ़िल्टरक्वेरी
टेक्स्टशामिल है, से शुरू होता है, बराबर हैcontains, starts_with, equals
पूर्ण संख्या, मुद्रासे, तकfrom, to 1234.56 के रूप में
तारीख़से, तकfrom, to 2026-03-31 के रूप में
क्षण (DateTime)से, तक (तारीख़ें)उपयोगकर्ता के समय क्षेत्र में पूरा दिन
समयसे, तक14:30
Choiceकोई भी विकल्प चुनेंany_of
हाँ/नहींसभी, हाँ, नहींis

मान उपयोगकर्ता की भाषा चाहे जो हो, एक निश्चित मशीन रूप में चलते हैं। पुराना { "field", "contains" } रूप अब भी काम करता है। सर्वर filter() के बिना कॉलम पर फ़िल्टर और ग्रिड में न होने वाले कॉलम पर क्रम हटा देता है, और फ़िल्टर (32), फ़िल्टर टेक्स्ट (200 अक्षर), विकल्प (100) और क्रम कुंजियाँ (4) सीमित करता है। जो मान पढ़ा न जा सके उसे अनदेखा किया जाता है। तारीख़ फ़िल्टर का समय क्षेत्र सर्वर पर उपयोगकर्ता की सेटिंग से आता है।

शीर्षक पर Shift+क्लिक उस कॉलम को क्रम कुंजियों में जोड़ता है। शीर्षक में एक संख्या क्रम दिखाती है।

कॉलम: पिन, आकार, छिपाना, हिलाना

pin_start() और pin_end() ग्रिड के बगल में स्क्रॉल होने पर कॉलम को एक किनारे पर रखते हैं (प्रति ओर अधिकतम तीन)। hidden() कॉलम को तब तक हटाए रखता है जब तक उपयोगकर्ता उसे न दिखाए। हर शीर्षक में कॉलम मेनू है (बटन, राइट क्लिक, Shift+F10 या संदर्भ मेनू कुंजी) जिसमें क्रम, पिन, बाएँ और दाएँ हिलाना, छिपाना, फ़िल्टर, कॉलम चयनकर्ता और रीसेट है। शीर्षक का किनारा कॉलम का आकार बदलता है, खींचकर या तीर कुंजियों से (बड़े कदमों के लिए Shift)। शीर्षक को उसी पिन समूह के दूसरे शीर्षक पर खींचना कॉलम को हिलाता है; छोटा दबाव अब भी क्रम लगाता है। यह सब दाएँ से बाएँ भी काम करता है।

सहेजे गए व्यू

उपयोगकर्ता का लेआउट (क्रम से दिखाए कॉलम, चौड़ाइयाँ, पिन), क्रम और फ़िल्टर DataGridView बनाते हैं। App::datagrid_views(store) के साथ यह सर्वर पर प्रति उपयोगकर्ता, हर टेनेंट, Screen और ग्रिड के लिए सहेजा जाता है, और पृष्ठ उसमें लौटता है जिसमें पहला पृष्ठ पहले से क्रमबद्ध और फ़िल्टर्ड होता है। डेटाबेस के लिए DataGridViewStore लागू करें; MemoryViewStore डेवलपमेंट और टेस्ट के लिए है। स्टोर के बिना ब्राउज़र व्यू को localStorage में रखता है। सर्वर हर प्राप्त व्यू को ग्रिड के अपने कॉलम और सीमाओं से साफ़ करता है।

सेल

मेथडकॉलमक्या दिखाता है
badge(|v| Tone)#[choice] enumहर विकल्प के लिए रंगीन बैज
progress(max)संख्याएँ, मुद्राएक पट्टी और संख्या
link(|row| Effect)कोई भीमान को ऐसे लिंक के रूप में जो effect चलाता है
check_icon()boolसही का निशान या डैश, स्क्रीन रीडर के लिए शब्दों के साथ
relative_time()DateTime"3 मिनट पहले", टूलटिप में सटीक समय
cell(renderer)कोई भीआपका अपना HTML (CellRenderer<T>)

CellRenderer को उपयोगकर्ता डेटा escape करना होगा। निर्यात और कॉपी सादा मान इस्तेमाल करते हैं।

पंक्ति action, मेनू और बल्क action

row_action(label, action, |row| input) हर पंक्ति में एक बटन जोड़ता है। row_menu(|row| ContextMenu) संदर्भ मेनू जोड़ता है। Screen::context_menu(...) Screen की खाली जगह पर एक जोड़ता है। जो आइटम action चलाते हैं वे केवल उन उपयोगकर्ताओं को दिखते हैं जिनके पास उस action की अनुमति है।

जब पंक्ति का आइटम चलता है, क्लाइंट केवल पंक्ति कुंजी और आइटम भेजता है। सर्वर पंक्ति को ग्रिड की action से फिर लोड करता है, उसी पंक्ति से आइटम बनाता है, action की अनुमति जाँचता है, इंटरसेप्टर चलाता है और फिर action। जो आइटम पंक्ति के लिए अब मौजूद नहीं है (उदाहरण के लिए, जो निष्क्रिय हो गया) अस्वीकार किया जाता है। इनपुट कभी क्लाइंट से नहीं आता।

bulk_action(label, action, Model::key) चयन पट्टी में एक बटन जोड़ता है। action Vec<K> लेती है, कुंजी फ़ील्ड का प्रकार; इसके अलावा कुछ भी कंपाइल नहीं होता। "सभी मेल खाती पंक्तियाँ" चुनने पर सर्वर उपयोगकर्ता के फ़िल्टर से खुद कुंजियाँ इकट्ठा करता है, 10,000 तक। एक-एक करके चुनी गई कुंजियाँ क्लाइंट से आती हैं, इसलिए action को हर रिकॉर्ड वैसे ही जाँचना होगा जैसे API action जाँचती।

ब्राउज़र बाकी हर जगह अपना संदर्भ मेनू रखता है। App::browser_context_menu(false) इसे टेक्स्ट इनपुट और संपादन योग्य टेक्स्ट को छोड़कर बंद करता है। यह किसी चीज़ की रक्षा नहीं करता: उपयोगकर्ता फिर भी पृष्ठ स्रोत पढ़ सकते हैं, डेवलपर टूल खोल सकते हैं या स्क्रिप्ट बंद कर सकते हैं। यह वर्तनी जाँच, लिंक कॉपी, अनुवाद और सहायक टूल भी छीन लेता है। डिफ़ॉल्ट रखें।

इनलाइन संपादन

edit_with(save) ऐसी action के साथ जो Valid<E> लेती है (फ़ॉर्म जैसा ही नियम) और कॉलम पर editable()। कुंजियाँ, केवल पढ़ने योग्य फ़ील्ड और पंक्ति संस्करण कभी संपादन योग्य नहीं बनते। संपादन योग्य सेल पर F2 या डबल क्लिक पंक्ति का संपादन शुरू करता है; Enter सहेजता है, Escape रद्द करता है, Ctrl+Z या टोस्ट बटन आखिरी सेव पूर्ववत करता है।

सर्वर पंक्ति को कुंजी से फिर लोड करता है और Form::read के ज़रिए केवल संपादन योग्य कॉलम और पंक्ति संस्करण लागू करता है, इसलिए मान वैसे ही पढ़े और सत्यापित होते हैं जैसे फ़ॉर्म में। किसी अन्य कॉलम का मान 403 से अस्वीकार होता है। पुराना संस्करण 409 के रूप में लौटता है, और सत्यापन त्रुटियाँ 422 के रूप में लौटती हैं और अपने सेल में दिखती हैं।

Master detail

detail(|row| (screen, params)) हर पंक्ति को पंक्ति से बनी Screen में फैलने देता है, केवल उपयोगकर्ता के खोलने पर लोड होती है:

DataGrid::of(search_today)
    .column(Order::id)
    .detail(|o| (order_lines, OrderParams { id: o.id }))

#[screen(permission = "sales.order.read")]
pub fn order_lines(params: OrderParams) -> Screen {
    Screen::window(t!("sales.order_lines", id = params.id.0.to_string())).body(
        DataGrid::of(search_lines)
            .scope(OrderLine::order_id, params.id)
            .column(OrderLine::product)
            .column(OrderLine::amount).sum()
            .detail(|l| (product_editor, ProductParams { id: Some(l.product_id) })),
    )
}

Params Screen द्वारा टाइप्ड हैं (ScreenDef::Params), इसलिए गलत params कंपाइल नहीं होते। detail पूरी Screen है: फ़ॉर्म, नेस्टेड ग्रिड, या अपने detail वाला ग्रिड, किसी भी गहराई तक। एक्सपैंडर कॉलम केवल उन उपयोगकर्ताओं को दिखता है जो Screen खोल सकते हैं, और detail लोड होने पर सर्वर Screen की अनुमति फिर जाँचता है। params ब्राउज़र से वैसे ही गुज़रते हैं जैसे Window के, इसलिए detail Screen को जाँचना होगा कि उपयोगकर्ता उस रिकॉर्ड को देख सकता है जिसे वे नाम देते हैं।

scope(field, value) ग्रिड को हर अनुरोध पर उन पंक्तियों तक सीमित रखता है जिनका field value के बराबर है। फ़िल्टर DataQuery::filters में सबसे पहले जाता है और क्लाइंट उसे हटा नहीं सकता, इसलिए ब्राउज़र कुछ भी भेजे नेस्टेड ग्रिड अपनी पैरेंट पंक्ति पर रहता है। फ़िल्टर से SQL बनाने वाली डेटा परत इसे किसी भी अन्य की तरह पढ़ती है (संख्याओं और तारीख़ों के लिए बराबर सीमाओं के साथ Filter::range, टेक्स्ट के लिए equals, choice के लिए any_of, हाँ/नहीं के लिए is, खाली मानों के लिए blank)।

एक्सपैंडर बटन, उस पर Enter, या पंक्ति पर Right और Left detail खोलते और बंद करते हैं। बंद करना उसे हटा देता है, इसलिए अगली बार वह ताज़ा लोड होता है।

वर्चुअल ग्रिड हर पंक्ति को एक निश्चित ऊँचाई पर रखते हैं ताकि किसी भी स्थिति तक तुरंत पहुँचा जा सके; वे एक्सपैंडर नहीं दिखाते। detail वाले ग्रिड के लिए पृष्ठ या अनंत पृष्ठांकन इस्तेमाल करें।

समूहन

group_by(field) सर्वर पर पंक्तियों को समूहित करता है; हर समूह के भीतर समूहित करने के लिए इसे फिर कॉल करें:

DataGrid::of(search_today)
    .paging(Paging::pages(20))
    .group_by(Order::city)
    .group_by(Order::status)
    .column(Order::amount).sum().avg()

ग्रिड हर समूह के लिए एक शीर्षक पंक्ति दिखाता है जिसमें कॉलम लेबल, मान, पंक्ति गिनती और उस समूह पर हर कॉलम योग, उसके कॉलम के नीचे, होते हैं। समूह खोलना (उसका बटन, या Right और Left) उसके उपसमूह या पंक्तियाँ लोड करता है, एक बार में एक पृष्ठ, और जब और बचे हों तो "और लोड करें" पंक्ति के साथ; बंद करना उन्हें हटा देता है। शीर्ष स्तर समूहों पर पृष्ठांकन करता है, इसलिए पेजर समूह गिनता है। फ़ुटर हर मेल खाती पंक्ति पर योग रखता है। समूहों के भीतर की पंक्तियाँ बाकी सब रखती हैं: संपादन, पंक्ति action, मेनू, चयन और detail।

डेटा परत DataQuery::group का उत्तर देती है: जब यह सेट हो, वह Page::groups लौटाती है (मान, गिनती और क्वेरी जो योग माँगती है, प्रति समूह) जो उस फ़ील्ड की क्रम कुंजी की दिशा में मान से क्रमबद्ध हो, पंक्तियों की तरह पृष्ठबद्ध, total समूह गिनते हुए। DataQuery::apply मेमोरी के डेटा के लिए यह करता है; SQL GROUP BY इस्तेमाल करता है। group ग्रिड सेट करता है और कभी क्लाइंट से नहीं पढ़ा जाता। क्लाइंट केवल समूह मानों का वह पथ भेजता है जिसे वह खोलता है; सर्वर उसकी लंबाई जाँचता है और हर मान को उस समूह के कॉलम पर फ़िल्टर में बदल देता है, उपयोगकर्ता के फ़िल्टर के आगे (खाली समूह के लिए blank)।

ट्री डेटा

tree(Model::parent) पंक्तियों को वैकल्पिक पैरेंट कुंजी से ट्री के रूप में दिखाता है: बिना पैरेंट वाली पंक्तियाँ शीर्ष पर, और पंक्ति की संतानें उसके खुलने पर, एक बार में एक पृष्ठ, अधिकतम 32 स्तर तक लोड होती हैं।

DataGrid::of(search_employees)
    .tree(Employee::manager_id)
    .column(Employee::name)
    .column(Employee::salary).sum()

पहला कॉलम इंडेंट और बटन रखता है। यह जानने के लिए कि किन पंक्तियों की संतानें हैं, ग्रिड प्रति पृष्ठ अपनी action से एक बार और पूछता है: वे पंक्तियाँ जिनका पैरेंट पृष्ठ की कुंजियों में से एक है, पैरेंट फ़ील्ड से समूहित (कुंजियों पर Filter::any_of और DataQuery::group)। फ़िल्टर और क्रम हर स्तर पर लागू होते हैं; फ़ुटर योग हर मेल खाती पंक्ति को कवर करते हैं। ट्री ग्रिड समूहन नहीं करते और पंक्ति detail नहीं दिखाते। इनलाइन संपादन के बाद पंक्ति ट्री में अपनी जगह रखती है।

वर्चुअल ग्रिड न समूहन करते हैं न ट्री दिखाते हैं, क्योंकि वहाँ हर पंक्ति की एक निश्चित ऊँचाई होती है।

सेल: नेविगेशन, कॉपी और पेस्ट

पंक्ति पर Right (या सेल पर क्लिक) उसमें सेल कर्सर रखता है, स्प्रेडशीट की तरह। तीर कुंजियाँ उसे चलाती हैं, तीर के साथ Shift (या Shift+क्लिक) रेंज बढ़ाता है, Home और End पंक्ति के सिरों पर जाते हैं और Ctrl+Home और Ctrl+End ग्रिड के पहले और आखिरी सेल पर। Tab और Shift+Tab पंक्ति के साथ और अगली पंक्ति पर चलते हैं, और सिरों पर ग्रिड छोड़ देते हैं। पहले सेल पर Left पंक्ति पर लौटता है। Enter या F2 संपादन योग्य सेल को संपादित करता है, Enter सेल का अकेला बटन या लिंक दबाता है, Escape रेंज छोड़ता है। रेंज के सेल aria-selected रखते हैं।

सेल पर Ctrl+C रेंज को टैब से अलग टेक्स्ट के रूप में कॉपी करता है, मान वैसे जैसे उपयोगकर्ता देखता है। पंक्ति पर Ctrl+C अब भी चुनी गई पंक्तियाँ कॉपी करता है।

सेल पर Ctrl+V स्प्रेडशीट से टैब से अलग टेक्स्ट कर्सर से पेस्ट करता है; एक मान पूरी रेंज भरता है। केवल संपादन योग्य सेल बदलते हैं (केवल पढ़ने योग्य सेल में पेस्ट करना यह बताता है), choice लेबल से पेस्ट किए जा सकते हैं, हाँ और नहीं उपयोगकर्ता के शब्दों में। हर बदली पंक्ति इनलाइन संपादन पथ (पंक्ति संस्करण के साथ /_zeyn/grid/edit) से सहेजी जाती है, एक के बाद एक, इसलिए हर पंक्ति सर्वर पर इनलाइन संपादन की तरह पढ़ी, सत्यापित और जाँची जाती है; विफल होने वाली पंक्ति अपने सेल में त्रुटियाँ दिखाती है और बाकी सहेजी जाती हैं। 10 से अधिक पंक्तियों पर पहले पूछा जाता है, 500 से अधिक अस्वीकार होती हैं, और Ctrl+Z पूरा पेस्ट पूर्ववत करता है। ग्रिड संपादन, पंक्ति action, बल्क action और मेनू action App::write_limit में गिने जाते हैं, इसलिए बड़ा पेस्ट ऐप की लेखन सीमा से टकरा सकता है।

कॉलम वर्चुअलाइज़ेशन

40 या अधिक कॉलम वाला ग्रिड पृष्ठ में केवल पिन किए कॉलम और दिख रहे कॉलम (साथ में हर ओर छह तक) रखता है। हर कॉलम को निश्चित चौड़ाई मिलती है, और एक स्पेसर सेल हर ओर छोड़े गए कॉलम के लिए खड़ा होता है, इसलिए चौड़ाइयाँ, पिन और स्क्रॉलिंग जैसे थे वैसे रहते हैं। पंक्तियाँ अपने सेल की पूरी सूची रखती हैं, इसलिए कॉपी, पेस्ट और संपादन हर कॉलम देखते हैं, और सेल aria-colindex रखते हैं। विंडो तभी हिलती है जब उसके बाहर का कॉलम दिखने में आता है। सर्वर अब भी पंक्ति का हर सेल भेजता है। इतना चौड़ा वर्चुअल ग्रिड (VIRTUAL_WIDE_COLUMNS, चयन, डिटेल और पंक्ति action कॉलम गिनकर) अपना पूरा पहला ब्लॉक 64 लाइव पंक्तियों की जगह <template data-zeyn-rows-later> के अंदर भेजता है, इसलिए ब्राउज़र कभी सभी कॉलम वाली पंक्ति का लेआउट नहीं बनाता: गैलरी के चौड़े ग्रिड पर सबसे लंबा स्टार्टअप कार्य 259 से 112 ms और DOMContentLoaded 402 से 228 ms हो गया (8 बारी-बारी से लोड की माध्यिका, रिलीज़ सर्वर, व्यस्त मशीन)।

गैलरी के चौड़े ग्रिड पर मापा गया (62 कॉलम, 100,000 पंक्तियाँ, वर्चुअल स्क्रॉलिंग, डिबग सर्वर, Chromium, 1400 बाय 900 विंडो, 144 Hz डिस्प्ले), कॉलम वर्चुअलाइज़ेशन के साथ और बिना:

पृष्ठ में सेलबगल में, 60 px प्रति फ़्रेम (p50 / p95)नीचे, 60 px प्रति फ़्रेम (p50 / p95)नीचे, 2,000 px प्रति फ़्रेम (p50 / p95)
बिना2,9766.9 / 7.5 ms42.7 / 64.8 ms78.5 / 141 ms, 178 लंबे कार्य
के साथ1,0567.0 / 28.8 ms24.6 / 41.7 ms28.9 / 48.9 ms, 7 लंबे कार्य

नीचे स्क्रॉल करना लगभग दोगुना तेज़ है और पृष्ठ में एक तिहाई सेल हैं। बगल में स्क्रॉलिंग पहले से सहज थी; जिन फ़्रेम में विंडो हिलती है उनमें 29 ms तक लगते हैं। बाकी लागत हर कॉलम के साथ 200 पंक्तियों के ब्लॉक पार्स करने की है, जिसे कॉलम वर्चुअलाइज़ेशन नहीं बदलता।

निर्यात

exportable() (और वैकल्पिक रूप से export_permission(...), export_limit(n)) टूलबार के Export::Csv बटन को हर मेल खाती पंक्ति डाउनलोड करने देता है। सर्वर ग्रिड की action से पृष्ठ दर पृष्ठ गुज़रता है और हर पृष्ठ को तुरंत स्ट्रीम करता है, उपयोगकर्ता के लेआउट और भाषा में। फ़ॉर्मूले निष्क्रिय किए जाते हैं। डिफ़ॉल्ट रूप से 100,000 पंक्तियों तक।

xlsx Cargo feature के साथ टूलबार का Export::Xlsx बटन वही पंक्तियाँ Excel वर्कबुक के रूप में डाउनलोड करता है (GET /_zeyn/grid/export?format=xlsx)। सेल अपने प्रकार रखते हैं: संख्याएँ, मुद्रा अपने करेंसी प्रारूप के साथ संख्या के रूप में, तारीख़ें और तारीख़-समय उपयोगकर्ता के समय क्षेत्र में असली Excel तारीख़ों के रूप में, और बूलियन। Choice अपने लेबल के रूप में लिखे जाते हैं, मास्क किए फ़ील्ड अपने मास्क किए टेक्स्ट के रूप में, और टेक्स्ट हमेशा टेक्स्ट रहता है, इसलिए कुछ भी फ़ॉर्मूला नहीं बनता। शीर्षक पंक्ति उपयोगकर्ता की भाषा में लेबल रखती है, बोल्ड और फ़्रीज़ होती है, और कॉलम उपयोगकर्ता का क्रम और चौड़ाइयाँ रखते हैं।

वर्कबुक rust_xlsxwriter से constant memory मोड में लिखी जाती है: हर पृष्ठ आते ही अस्थायी फ़ाइल में जाता है (अधिकतम दो पृष्ठ मेमोरी में इंतज़ार करते हैं), और ज़िप की गई वर्कबुक अंत में उत्तर में स्ट्रीम होती है। छह कॉलम की 100,000 पंक्तियों का निर्यात पंक्तियाँ लिखते समय हीप को लगभग 134 KiB पर रखता रहा (10,000 और 100,000 पंक्तियों के बाद भी वही) और ज़िप करते समय 460 KiB; फ़ाइल 3.4 MB की थी।

pdf Cargo feature के साथ Export::Pdf वही पंक्तियाँ सूची रिपोर्ट के रूप में छापता है (अधिकतम 2,000 पंक्तियाँ); देखें PDF दस्तावेज़।

चयन

selectable() (bulk_action से निहित) चेकबॉक्स कॉलम जोड़ता है। Shift रेंज चुनता है, Space फ़ोकस की गई पंक्ति चुनता है, और शीर्षक बॉक्स पृष्ठ चुनता है। चयन पट्टी हर मेल खाती पंक्ति प्रस्तुत करती है।

सुगम्यता

तालिका में role="grid", aria-rowcount (वर्चुअल ग्रिड), aria-colcount, aria-colindex और aria-sort हैं। पंक्तियाँ roving tab stop इस्तेमाल करती हैं। सक्रिय पंक्ति के भीतर के बटन Tab से पहुँच योग्य हैं। समूहित और ट्री ग्रिड role="treegrid" हैं जिनकी पंक्तियों पर aria-level और aria-expanded है। मेनू menuitem, menuitemcheckbox और menuitemradio के साथ role="menu" इस्तेमाल करते हैं, और फ़ोकस वहीं लौटता है जहाँ था। खाली और त्रुटि स्थितियाँ घोषित होती हैं (role="status")।

प्रदर्शन

शोकेस संग्रह (1,000,000 पंक्तियाँ, वर्चुअल स्क्रॉलिंग, डिबग सर्वर, Chromium, 144 Hz डिस्प्ले) पर Performance API से मापा गया:

स्क्रॉलफ़्रेम p50फ़्रेम p95अधिकतमलंबे कार्य
व्हील गति (60 px प्रति फ़्रेम)13.9 ms20.9 ms34.6 ms0
तेज़ (2,000 px प्रति फ़्रेम)14.1 ms27.8 ms54.9 ms0
पूरी सूची पर स्वीप13.9 ms27.8 ms48.6 ms0

DOM में 62 पंक्तियाँ हैं (लगभग 660 एलिमेंट), और JS हीप लगभग 4 MB पर रहता है। उसी संग्रह से 100,000 पंक्तियों का निर्यात 3.4 सेकंड में 7 MB स्ट्रीम हुआ।

स्क्रीन बिल्डर को सस्ता रखें

अनुरोध स्टेटलेस हैं, इसलिए ग्रिड का हर अनुरोध उस स्क्रीन को फिर से बनाता है जिसमें ग्रिड है: वर्चुअल ग्रिड का हर ब्लॉक (हर 200 पंक्तियाँ स्क्रॉल करने पर), हर पृष्ठ, सॉर्ट, फ़िल्टर और निर्यात, हर इनलाइन संपादन और हर पंक्ति action ग्रिड का action चलाने से पहले #[screen] फ़ंक्शन को फिर से चलाता है। सर्वर को ग्रिड को उसके नोड पाथ से खोजने और एक्सेस जाँचने के लिए स्क्रीन चाहिए, इसलिए प्रति उपयोगकर्ता स्टेट न रखने की यही कीमत है।

जो बिल्डर केवल कॉम्पोनेंट सजाता है उसकी लागत माइक्रोसेकंड है। जो बिल्डर डेटाबेस से क्वेरी करता है वह हर ऐसे अनुरोध पर वह क्वेरी चुकाता है। इसलिए:

  • पंक्तियाँ ग्रिड के action (DataGrid::of(search)) में लोड करें। वह वैसे भी हर अनुरोध में एक बार चलता है और उसे पृष्ठ, सॉर्ट और फ़िल्टर के साथ DataQuery मिलती है।
  • विकल्प और लुकअप फ़ील्ड टाइप (#[choice]), फ़ॉर्म लुकअप (Form::lookup, जो उपयोगकर्ता के टाइप करने पर अपना action पूछता है) या ऐसी सर्विस में रहें जो उन्हें सीमित कैश में रखती है, बिल्डर की चलाई क्वेरी में नहीं।
  • जब किसी स्क्रीन को रिकॉर्ड लोड करना पड़े (Form::of(record)), तो बड़े या वर्चुअल ग्रिड को उससे दूर रखें: उन्हें अपनी स्क्रीन, डिटेल स्क्रीन (DataGrid::detail) या विंडो में रखें, ताकि उनके ब्लॉक अनुरोध ऐसी स्क्रीन बनाएँ जो कुछ लोड नहीं करती।
  • स्क्रीन params बिल्डर का इनपुट हैं; उन्हें कुंजियों तक सीमित रखें, और ग्रिड के action को उनसे फ़िल्टर करने दें (DataGrid::scope)।