جافاسكربت developer_modeتطوير الويب

AG Grid الدليل الشامل الأول

AG Grid الدليل الشامل لإنشاء جداول بيانات ديناميكية ومتقدمة باستخدام JavaScript. تعلم كيفية استخدام AG Grid مع ميزات مثل الفرز، التصفية، التمرير الافتراضي، وتحسين الأداء في التطبيقات الحديثة.

ما هي Data Grid؟

Data Grid هي عبارة عن جدول متقدم يقدم مميزات تتجاوز الجداول التقليدية المستخدمة في تطوير الواجهات. يمكن اعتبارها بمثابة برنامج “إكسل” مصغر، حيث تتيح للمستخدمين التعامل مع البيانات بطريقة ديناميكية وسلسة.

مميزات Data Grid العامة

  • فرز البيانات: السماح بترتيب البيانات تصاعديًا أو تنازليًا.
  • تصفية البيانات: عرض البيانات بناءً على شروط محددة.
  • التحرير المباشر: تعديل البيانات مباشرة داخل الجدول.
  • التنقل بين الصفوف والأعمدة بسهولة: محاكاة لتجربة برنامج الإكسل.
  • التكامل مع قواعد البيانات أو APIs: لتحميل البيانات وعرضها في الوقت الفعلي.

AG Grid كمثال على Data Grid

Ag-Grid هو مكتبة جافا سكربت قوية ومتقدمة لإنشاء الجداول (الـ Grids) في تطبيقات الويب. تتيح هذه المكتبة للمطورين عرض البيانات بشكل تفاعلي ومرن، مع مجموعة واسعة من الميزات مثل التصفية، الفرز، التمرير، التحديد المتعدد، والتعديل على الخلايا، مما يجعلها مثالية لاستخدامها في التطبيقات التي تحتاج إلى عرض بيانات كبيرة ومعقدة.

تثبيت AG Grid

قم بإضافة رابط سكربت AG Grid لصفحة HTML الخاصة بك.

<html lang="en">
 <head>
   <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
 </head>
 <body>
   <!-- Your Data Grid container -->
   <div id="myGrid"></div>
   
   <script>
   
   </script>
 </body>
</html>
HTML

اكتب الكود التالي بداخل script tag في الكود السابق:


const gridOptions = {};


const myGridElement = document.querySelector('#myGrid');
agGrid.createGrid(myGridElement, gridOptions);
JavaScript

قم بتزويد أعمدة وصفوف الجدول لـــ AG Grid:

const gridOptions = {
  // بيانات الصفوف
  rowData: [
    { title: "1984", author: "جورج أورويل", year: 1949, available: true },
    { title: "الغيتا: أغنية كريشنا", author: "مترجم مجهول", year: -300, available: true },
    { title: "البؤساء", author: "فيكتور هوغو", year: 1862, available: false },
    { title: "مئة عام من العزلة", author: "غابرييل غارسيا ماركيز", year: 1967, available: true },
  ],
  // تعريف الأعمدة
  columnDefs: [
    { field: "title", headerName: "عنوان الكتاب", sortable: true, filter: true },
    { field: "author", headerName: "المؤلف", sortable: true, filter: true },
    { field: "year", headerName: "سنة النشر", sortable: true, filter: "agNumberColumnFilter" },
    { 
      field: "available", 
      headerName: "متوفر", 
      cellRenderer: (params) => (params.value ? "✅ متاح" : "❌ غير متاح") 
    },
  ],
};
JavaScript

أساسيات AG Grid

ستقوم بتخصيص ag grid لاستخدامك بضبط الاعدادات بداخل grid options. أيضاً هنالك خيارات تخصيص يمكن اضافتها لتعريف الأعمدة.

الخيارات العامة

في الجدول الآتي ستجد الخيارات العامة التي يمكنك اضافتها لخيارات grid options :

اسم الخيارالوصف
rowDataتحديد البيانات التي ستُعرض في الجدول، على شكل مصفوفة من الكائنات.
columnDefsتعريف الأعمدة وإعداداتها مثل الاسم، الفرز، والتصفية.
defaultColDefتحديد الإعدادات الافتراضية لجميع الأعمدة لتقليل التكرار.
enableRtltrue لدعم اللغات التي تكتب من اليمين لليسار كاللغة العربية.
paginationتمكين ميزة التقسيم والترقيم للبيانات الكبيرة.
paginationPageSizeتحديد عدد الصفوف التي ستُعرض في كل صفحة عند تمكين التقسيم في الصفحات.
onGridReadyوظيفة يتم استدعاؤها عند تجهيز الجدول بشكل كامل.
rowHeightضبط ارتفاع كل صف في الجدول.

مثال على الخيارات العامة

const gridOptions = {
  rowData: [
    { title: '1984', author: 'جورج أورويل', year: 1949, available: true },
    { title: 'الغيتا: أغنية كريشنا', author: 'مترجم مجهول', year: -300, available: true },
    { title: 'البؤساء', author: 'فيكتور هوغو', year: 1862, available: false },
    { title: 'مئة عام من العزلة', author: 'غابرييل غارسيا ماركيز', year: 1967, available: true },
  ],
  columnDefs: [
    {
      field: 'title',
      headerName: 'عنوان الكتاب',
    },
    {
      field: 'author',
      headerName: 'المؤلف',
    },
    {
      field: 'year',
      headerName: 'سنة النشر',
    },
    {
      field: 'available',
      headerName: 'متوفر',
      cellRenderer: (params) => (params.value ? '✅ متاح' : '❌ غير متاح'),
    },
  ],
  enableRtl: true,
  rowHeight: 40,
  pagination: true,
  paginationPageSize: 1,
};
JavaScript

خيارات تخصيص الأعمدة

يتم تخصيص عرض الأعمدة بعدة خصائص، سيتم عرضها بالجدول الآتي:

الخاصيةالوصفأمثلة
fieldتُستخدم لتحديد اسم الحقل من البيانات (rowData) الذي سيتم عرضه في العمود.{ field: 'title' }
headerNameتُحدد النص الذي سيتم عرضه كعنوان للعمود في رأس الجدول.{ headerName: 'عنوان الكتاب' }
filterتُحدد ما إذا كان يمكن تصفية العمود أم لا. يمكن أن تكون قيمة true لتمكين التصفية الافتراضية، أو نوع معين مثل 'agNumberColumnFilter'.{ filter: true } أو { filter: 'agTextColumnFilter' }
sortableتُحدد ما إذا كان يمكن ترتيب البيانات في هذا العمود بالنقر على رأس العمود.{ sortable: true }
cellRendererتُتيح تخصيص مظهر الخلية أو إضافة تنسيق معين (مثل الرموز أو النصوص المخصصة) .{ cellRenderer: (params) => params.value ? '✅' : '❌' }

مثال على خيارات تخصيص الأعمدة

<!doctype html>
<html lang="ar" dir="ltr">
  <head>
    <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
    <style>
      .container {
        max-width: 1200px;
        margin: 2rem auto;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div id="myGrid" class="ag-theme-alpine" style="height: 300px"></div>
    </div>

    <script>
      const gridOptions = {
        rowData: [
          { title: '1984', author: 'جورج أورويل', year: 1949, available: true },
          {
            title: 'الغيتا: أغنية كريشنا',
            author: 'مترجم مجهول',
            year: -300,
            available: true,
          },
          {
            title: 'البؤساء',
            author: 'فيكتور هوغو',
            year: 1862,
            available: false,
          },
          {
            title: 'مئة عام من العزلة',
            author: 'غابرييل غارسيا ماركيز',
            year: 1967,
            available: true,
          },
        ],
        // تعريف الأعمدة
        columnDefs: [
          {
            field: 'title',
            headerName: 'عنوان الكتاب',
            sortable: false,
            filter: false,
          },
          {
            field: 'author',
            headerName: 'المؤلف',
            sortable: true,
            filter: true,
          },
          {
            field: 'year',
            headerName: 'سنة النشر',
            sortable: true,
            filter: 'agNumberColumnFilter',
          },
          {
            field: 'available',
            headerName: 'متوفر',
            cellRenderer: (params) => {
              return params.value ? '✅ متاح' : '❌ غير متاح';
            },
          },
        ],
        enableRtl: true,
        rowHeight: 40,
        pagination: true,
        paginationPageSize: 1,
      };
      const myGridElement = document.querySelector('#myGrid');
      agGrid.createGrid(myGridElement, gridOptions);
    </script>
  </body>
</html>
HTML

خيارات متقدمة في الأعمدة

هنالك خيارات متقدمة يمكن اضافتها للأعمدة للمساعدة في تنسيق عرض البيانات في الجدول.

الخاصيةالوصفأمثلة
Cell Renderer Imageتُستخدم لتخصيص الخلية بحيث تعرض صورة بناءً على البيانات.{ cellRenderer: (params) => '<img src="' + params.value + '" />' }
Cell Renderer تُستخدم لدمج حقول متعددة وعرضها في خلية واحدة بطريقة مخصصة، مثل الاسم الكامل (الاسم الأول + الأخير).{ cellRenderer: (params) => params.data.firstName + ' ' + params.data.lastName }
valueGetterتُتيح تخصيص كيفية استرداد القيمة للعرض أو الاستخدام من مصدر البيانات، بدلًا من عرض الحقل مباشرة.{ valueGetter: (params) => params.data.firstName + ' ' + params.data.lastName }
valueFormatterتُستخدم لتنسيق القيم التي سيتم عرضها في الخلية، مثل تنسيق الأرقام أو التواريخ أو النصوص.{ valueFormatter: (params) => params.value.toFixed(2) + ' USD' }
cellClassRuleتُستخدم لتطبيق أنماط CSS على خلايا بناءً على شروط معينة (قواعد).{ cellClassRules: { 'highlight': (params) => params.value > 100 } }

شرح سريع لكل خاصية:

  1. Cell Renderer Image:
    تُستخدم لعرض صور ديناميكية في خلايا الجدول، حيث يتم جلب الصور بناءً على البيانات المرسلة من مصدر البيانات (مثل رابط الصورة).
  2. Cell Renderer Full Name:
    تُتيح تخصيص النصوص داخل الخلية لعرض بيانات مدمجة أو معدّلة، مثل جمع الاسم الأول والاسم الأخير في خلية واحدة.
  3. valueGetter:
    تُتيح حساب أو تخصيص القيمة التي ستُعرض في الخلية بناءً على العمليات أو البيانات الأخرى الموجودة في الصف.
  4. valueFormatter:
    تُستخدم لتنسيق القيم المرئية، مثل تحويل الأرقام إلى عملات، أو التواريخ إلى صيغة معينة.
  5. cellClassRule:
    تُتيح تطبيق تنسيقات CSS شرطية بناءً على القيم الموجودة في الصفوف، مثل تلوين الخلية إذا تجاوزت قيمة معينة.

مثال على الخيارات المتقدمة في تنسيق الأعمدة

columnDefs: [
  {
    field: 'photo',
    headerName: 'الصورة',
    cellRenderer: (params) => '<img src="' + params.value + '" style="width:50px;" />',
  },
  {
    headerName: 'الاسم الكامل',
    valueGetter: (params) => params.data.firstName + ' ' + params.data.lastName,
  },
  {
    field: 'price',
    headerName: 'السعر',
    valueFormatter: (params) => params.value.toFixed(2) + ' USD',
  },
  {
    field: 'quantity',
    headerName: 'الكمية',
    cellClassRules: { 'highlight': (params) => params.value > 100 },
  },
];
JavaScript

خيارات التحكم في الصفوف

أيضاً يمكن التحكم في تنسيق الصفوف.

الخاصيةالوصفأمثلة
RowClassRulesتُستخدم لتطبيق أنماط CSS على الصفوف بناءً على شروط معينة، مما يساعد في تمييز صفوف محددة بناءً على البيانات.{ rowClassRules: { 'row-highlight': (params) => params.data.value > 100 } }
Select Multiple Rowsتُتيح للمستخدم اختيار أكثر من صف في الجدول عن طريق تفعيل خيار التحديد المتعدد.rowSelection: {
mode: 'multiRow',
},

شرح الخصائص:

RowClassRules:

  • تُتيح إضافة أنماط CSS إلى الصفوف بناءً على شروط معينة.
  • مثال: يمكن تغيير لون الصف إذا تجاوزت قيمة معينة.

Select Multiple Rows:

  • تُفعل خيار تحديد أكثر من صف في نفس الوقت.
  • يمكن للمستخدم اختيار الصفوف باستخدام الضغط على Ctrl (أو Cmd في أجهزة Mac) أو باستخدام التحديد بالسحب.

مثال على تنسيق الصفوف

const gridOptions = {
  rowClassRules: {
    'row-highlight': (params) => params.data.value > 100, // يضيف CSS إذا القيمة > 100
    'row-disabled': (params) => !params.data.active,     // يضيف CSS إذا كان الحقل "active" غير موجود أو false
  },
   rowSelection: {
    mode: 'multiRow',
  },

};
JavaScript

محرر الخلايا Cell Editor

يمكن اضافة خاصية تحرير الخلايا لجعل خلايا الجدول قابلة للتعديل.

نوع المحررالوصفأمثلة
Text Cell Editorيُستخدم لإدخال نصوص بسيطة في الخلية.{ editable: true, cellEditor: 'agTextCellEditor' }
Large Text Editorيُستخدم لتحرير النصوص الطويلة، ويعرض مربع نص كبير (textarea) لتسهيل الكتابة.{ editable: true, cellEditor: 'agLargeTextCellEditor' }
Checkbox Editorيُتيح للمستخدم اختيار القيم بين حالتين (true/false) باستخدام مربع اختيار (Checkbox).{ editable: true, cellEditor: 'agCheckboxCellEditor' }
Date Editorيُتيح إدخال التواريخ باستخدام أداة اختيار التاريخ (Date Picker) لتجنب الأخطاء.{ editable: true, cellEditor: 'agDateCellEditor' }
Number Editorيُستخدم لإدخال قيم رقمية فقط مع إمكانية تخصيص القيود مثل الحد الأدنى أو الأقصى.{ editable: true, cellEditor: 'agNumberCellEditor', cellEditorParams: { min: 0, max: 100 } }

توضيح حول المحررات

  • agTextCellEditor:
    • المحرر الافتراضي للنصوص.
    • بسيط وسريع للاستخدام لإدخال النصوص القصيرة.
  • agLargeTextCellEditor
    • يعرض نافذة نص أكبر لتسهيل إدخال النصوص الطويلة.
    • مفيد عند التعامل مع أوصاف أو ملاحظات مطوّلة.
  • agCheckboxCellEditor
    • مفيد لحقول البيانات الثنائية (Boolean) مثل الحالة (مفعل/معطل).
    • يسمح بالتبديل بسهولة بين القيم.
  • agDateCellEditor
    • يوفّر إدخالًا أكثر دقة للتواريخ باستخدام منتقي التواريخ (Date Picker).
    • يساعد في تجنب الأخطاء الناتجة عن الإدخال اليدوي.
  • agNumberCellEditor
    • مخصص لإدخال القيم الرقمية فقط.
    • يمكن تخصيص قيود مثل الحدود الدنيا والقصوى لتقييد الإدخال.

مثال على استخدام AG GRID Editors

<!doctype html>
<html lang="ar" dir="ltr">
  <head>
    <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
    <style>
      .container {
        max-width: 1200px;
        margin: 2rem auto;
      }
      .green {
        background: green;
        color: white;
      }
      .red {
        background: red;
        color: white;
      }
      .orange {
        background: orange;
        color: white;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div id="myGrid" class="ag-theme-alpine" style="height: 300px"></div>
    </div>

    <script>
      const gridOptions = {
        rowData: [
          {
            rating: 80,
            date: '2022-11-17T08:00:00Z',
            price: '100',
            currency: 'Euros',
            title: '1984',
            author: 'جورج أورويل',
            year: 1949,
            available: true,
            image:
              'https://www.pixelstalk.net/wp-content/uploads/2016/09/Best-Beautiful-Images-For-Desktop-Nature.png',
            fullName: {
              firstName: 'George',
              lastName: 'orwell',
            },
          },
          {
            rating: 100,
            date: '2024-08-17T08:00:00Z',
            price: 50,
            currency: 'USD',
            title: 'الغيتا: أغنية كريشنا',
            author: 'مترجم مجهول',
            year: -300,
            available: true,
            image: 'https://mcdn.wallpapersafari.com/medium/75/57/6WLKOD.jpg',
            fullName: {
              firstName: 'Krishna',
              lastName: 'Krishna',
            },
          },
          {
            rating: 45,
            date: '2027-09-07T08:00:00Z',
            price: 2,

            currency: 'JOD',
            title: 'البؤساء',
            author: 'فيكتور هوغو',
            year: 1862,
            available: false,
            image: 'https://mcdn.wallpapersafari.com/medium/79/15/6sRwB7.jpg',
            fullName: {
              firstName: 'Victor',
              lastName: 'Hugo',
            },
          },
          {
            rating: 50,
            date: '2025-11-17T12:15:00Z',
            price: 20,
            currency: 'USD',
            title: 'مئة عام من العزلة',
            author: 'غابرييل غارسيا ماركيز',
            year: 1967,
            available: true,
            image:
              'https://wallup.net/wp-content/uploads/2016/03/10/319576-photography-landscape-nature-water-grass-trees-plants-sunrise-lake.jpg',
            fullName: {
              firstName: 'Gab',
              lastName: 'Markez',
            },
          },
        ],
        // تعريف الأعمدة
        columnDefs: [
          {
            field: 'title',
            headerName: 'عنوان الكتاب',
            sortable: false,
            filter: false,
          },
          {
            field: 'author',
            headerName: 'المؤلف',
            sortable: true,
            filter: true,
          },
          {
            field: 'year',
            headerName: 'سنة النشر',
            sortable: true,
            filter: 'agNumberColumnFilter',
          },
          {
            field: 'available',
            headerName: 'متوفر',
            cellRenderer: (params) => {
              return params.value ? '✅ متاح' : '❌ غير متاح';
            },
          },
          {
            field: 'image',
            headerName: 'Nice Image',
            cellRenderer: (params) => {
              if (params.value) {
                return `<img src="${params.value}" alt="image thumb" style="width:50px;
                height: 50px; border-radius: 50%">`;
              }
              return '';
            },
          },
          {
            field: 'fullName',
            headerName: 'Full Name',
            cellRenderer: (params) =>
              params?.value?.firstName + ' ' + params?.value?.lastName,
          },
          {
            field: 'formattedPrice',
            headerName: 'Price',
            valueGetter: (params) => {
              return params.data.price + ' ' + params.data.currency;
            },
          },
          {
            field: 'date',
            headerName: 'Update Date',
            valueFormatter: (params) => {
              const date = new Date(params.value);
              const formattedDate = date.toLocaleString('ar-JO', {
                year: 'numeric',
                month: 'long',
                day: 'numeric',
              });
              return formattedDate;
            },
          },
          {
            field: 'rating',
            headerName: 'Rating',
            cellClassRules: {
              green: (params) => params.value >= 80,
              red: (params) => params.value <= 45,
              orange: (params) => params.value > 45 && params.value < 80,
            },
          },
        ],
        enableRtl: true,
        rowHeight: 60,
        rowSelection: {
          mode: 'multiRow',
        },
        rowClassRules: {
          red: (params) => params.data.available === false,
        },
        pagination: true,
        paginationPageSize: 1,
      };
      const myGridElement = document.querySelector('#myGrid');
      const gridApi = agGrid.createGrid(myGridElement, gridOptions);
    </script>
  </body>
</html>
HTML

Grid API

Grid API هو مجموعة من الأدوات والوظائف التي توفرها agGrid للتفاعل مع الجدول برمجيًا. تُتيح هذه الواجهة التحكم في الجدول وإدارته، مثل تحديث البيانات، التصفية، الفرز، التحديد، أو التفاعل مع الصفوف والأعمدة.

وظائف Grid API

  • إدارة البيانات: يمكنك إضافة أو تعديل أو حذف الصفوف بسهولة باستخدام وظائف مثل applyTransaction.
  • التحكم في العرض: يمكنك تحديث الصفوف أو إعادة ترتيب الأعمدة أو التحكم في حجم الجدول.
  • التفاعل مع المستخدم: يمكنك معرفة ما حدده المستخدم، مثل الصفوف المحددة، باستخدام getSelectedRows.
  • المرونة في التخصيص: يسمح لك بالتلاعب بالتصفية والفرز برمجيًا

كيفية الحصول على Grid API

يمكنك الحصول على API بعد انشاء Grid Instance

const myGridElement = document.querySelector('#myGrid');
const gridApi = agGrid.createGrid(myGridElement, gridOptions);

console.log(gridApi);
JavaScript

أمثلة على Grid API

الحصول على السطور المحددة getSelectedRows

<!doctype html>
<html lang="ar" dir="ltr">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>جدول باستخدام agGrid</title>
    <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
  </head>
  <body>
    <div class="container">
      <!-- زر مخصص للحصول على الصفوف المحددة -->
      <button id="customBtn">Get Selected</button>

      <!-- عنصر الجدول -->
      <div id="myGrid" class="ag-theme-alpine" style="height: 300px"></div>
    </div>

    <script>
      // خيارات الجدول
      const gridOptions = {
        rowData: [
          { title: '1984' },
          { title: 'الغيتا: أغنية كريشنا' },
          { title: 'البؤساء' },
          { title: 'مئة عام من العزلة' },
        ],
        columnDefs: [
          {
            field: 'title',
            headerName: 'عنوان الكتاب',
          },
        ],
        enableRtl: true, // تمكين اتجاه النص من اليمين لليسار
        rowHeight: 60, // ارتفاع الصفوف
        rowSelection: { // تحديد سطر أو أكثر
          mode: 'multiRow',
        },
      };

      // إنشاء الجدول
      const myGridElement = document.querySelector('#myGrid');
      const gridApi = agGrid.createGrid(myGridElement, gridOptions);

      // وظيفة للحصول على الصفوف المحددة
      const btn = document.getElementById('customBtn');
      btn.addEventListener('click', () => {
        const selectedRows = gridApi.getSelectedRows();
        console.log(selectedRows);
      });
    </script>
  </body>
</html>
HTML

حذف السطور المحددة ApplyTransaction add

<!doctype html>
<html lang="ar" dir="ltr">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>جدول باستخدام agGrid</title>
    <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
  </head>
  <body>
    <div class="container">
      <button id="deleteRows">delete Rows</button>
      <!-- عنصر الجدول -->
      <div id="myGrid" class="ag-theme-alpine" style="height: 300px"></div>
    </div>

    <script>
      // خيارات الجدول
      const gridOptions = {
        rowData: [
          { title: '1984' },
          { title: 'الغيتا: أغنية كريشنا' },
          { title: 'البؤساء' },
          { title: 'مئة عام من العزلة' },
        ],
        columnDefs: [
          {
            field: 'title',
            headerName: 'عنوان الكتاب',
          },
        ],
        enableRtl: true, // تمكين اتجاه النص من اليمين لليسار
        rowHeight: 60, // ارتفاع الصفوف
        rowSelection: {
          mode: 'multiRow',
        },
      };

      // إنشاء الجدول
      const myGridElement = document.querySelector('#myGrid');
      const gridApi = agGrid.createGrid(myGridElement, gridOptions);

      // حذف السطور
      const deleteBtn = document.getElementById('deleteRows');
      deleteBtn.addEventListener('click', deleteRowsFunc);
      function deleteRowsFunc() {
        const selectedRows = gridApi.getSelectedRows();
        gridApi.applyTransaction({
          remove: selectedRows,
        });
      }
    </script>
  </body>
</html>
HTML

اضافة سطر جديد applyTransaction add

<!doctype html>
<html lang="ar" dir="ltr">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>جدول باستخدام agGrid</title>
    <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
  </head>
  <body>
    <div class="container">
      <button id="addRow">Add Row</button>
      <!-- عنصر الجدول -->
      <div id="myGrid" class="ag-theme-alpine" style="height: 300px"></div>
    </div>

    <script>
      // خيارات الجدول
      const gridOptions = {
        rowData: [
          { title: '1984' },
          { title: 'الغيتا: أغنية كريشنا' },
          { title: 'البؤساء' },
          { title: 'مئة عام من العزلة' },
        ],
        columnDefs: [
          {
            field: 'title',
            headerName: 'عنوان الكتاب',
          },
        ],
        enableRtl: true, // تمكين اتجاه النص من اليمين لليسار
        rowHeight: 60, // ارتفاع الصفوف
        rowSelection: {
          mode: 'multiRow',
        },
      };

      // إنشاء الجدول
      const myGridElement = document.querySelector('#myGrid');
      const gridApi = agGrid.createGrid(myGridElement, gridOptions);
      // اضافة سطر جديد
      const addBtn = document.getElementById('addRow');
      addBtn.addEventListener('click', addRowFunc);
      function addRowFunc() {
        const newRow = {
          title: 'new book'
        };
        gridApi.applyTransaction({
          add: [newRow],
        });
      }
    </script>
  </body>
</html>
HTML