จัดการข้อมูลด้วย SQL Database โดยใช้ Sqflite ใน Flutter

เขียนเมื่อ 3 ปีก่อน โดย Ninenik Narkdee
intl ฐานข้อมูล sqflite sqlite database flutter

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ intl ฐานข้อมูล sqflite sqlite database flutter

ดูแล้ว 13,698 ครั้ง




เนื้อหาตอนต่อไปนี้จะมาแนะนำ การบันทึกข้อมูลไว้ใน app
ในรูปแบบ SQLite database โดยใช้ package ที่ชื่อว่า Sqflite
โดยเนื้อหาจะเน้นไปที่ตัวอย่างโค้ด และการประยุกต์ มากกว่า
การอธิบายทีละส่วน เพราะในการใช้งานมีรายละเอีอดค่อน
ข้างมาก ดังนั้นจึงไว้วิธีแสดงเป็นภาพรวมแทน
 
   *เนื้อหานี้ใช้เนื้อหาต่อเนื่องจากบทความตอนที่แล้ว http://niik.in/1046
 
 

ลำดับสิ่งที่เราจะทำ

    สิ่งที่จะทำเป็นแนวทางการใช้งาน คือ จะสร้างระบบจำลองการเพิ่ม ลบ แก้ไข
เกี่ยวกับรายการหนังสือ ลงในฐานข้อมูล โดยการเพิ่มข้อมูล จะไม่เริ่มไปถึงขึ้นตอน
การสร้างฟอร์มกรอกข้อมูลใดๆ แต่จะใช้ข้อมูลทดสอบ ที่มีรูปแบบถูกต้องสำหรับ
บันทึกลงฐานข้อมูล และเน้นไปที่การทำงานกับฐานข้อมูลในรูปแบบต่างๆ ทั้งการ
เพิ่ม ลบ แก้ไข แสดงรายการทั้งหมด แสดงเฉพาะรายการ ล้างข้อมูลทั้งหมด เป็นต้น
 
    ดูตัวอย่างการทำงานตามรูป
 
 


 
 
    เราเชื่อมไปยังหน้าหนังสือ เริ่มต้นจะยังไม่มีรายการใดๆ จากนั้นกดเพิ่มจำนวน 6 รายการ
จากนั้นกดแสดงรายละเอียดรายการที่ 4 กดปิด จากนั้นกดลบรายการที่ 4 ออกไป ต่อด้วย
แก้ไขรายการที่ 3 สังเกตมีคำว่า new หลังจากแก้ไข และสุดท้ายกด ลบทั้งหมด รายการหาย
ไปจากฐานข้อมูล
 
 
 

เตรียมพร้อมก่อนใช้งาน SQLite database

    เราจะทำการติดตั้ง package ที่ชื่อว่า Sqflite สำหรับจัดการฐานข้อมูล SQLite และติดตั้ง
package ชื่อ intl สำหรับจัดการรูปแบบข้อมูลวันที่
 

     ติดตั้ง Sqflite และ Intl 

     เพิ่มไปในส่วนของไฟล์ pubspec.yaml 
 
dependencies:
  sqflite: ^2.3.3+1
  intl: ^0.19.0
 
    การ import ไปใช้งาน
 
// สำหรับ sqflite
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

// สำหรับ intl
import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl.dart';
 
    
    ไฟล์ที่เกี่ยวข้อง
    เราจะมีไฟล์ที่เกี่ยวข้องอยู่แค่ 3 ไฟล์ ดังนี้
 
    - lib > screen > book.dart
    - lib > models > book_model.dart
    - lib > db > book_db.dart
 
    โครงสร้างและ path ของไฟล์ตามรูปแบบด้านบน ไฟล์ book.dart เราจะใช้สำหรับจำลองการทำงาน
หลังจากเตรียมส่วนของการทำงานกับฐานข้อมูล และส่วนของข้อมูลไปแล้ว
    ไฟล์ book_db.dart จะเป็นไฟล์ที่รวมเกี่ยวกับฐานข้อมูลหนังสือทั้งหมด เป็นรูปแบบคำสั่งที่รองรับการ
เชื่อมต่อฐานข้อมูล สร้างตาราง เพิ่ม ลบ แก้ไข ข้อมูลในตาราง จะอยู่ในไฟล์นี้ เวลาเอาไปปรับใช้ ก็แก้ไข
เฉพาะส่วนที่ต้องการได้ 
    ไฟล์ book_model.dart เป็นไฟล์ที่รวมการกำหนดลักษณะของข้อมูล รวมถึงฟิลด์ข้อมูลในตารางที่จะใช้
ร่วมกับไฟล์ book_db.dart 
 
    จะเขียนคำอธิบายทั้งหมดไว้ในแต่ละไฟล์ 
 
 

    การเตรียมข้อมูล Data Model

 
    ไฟล์ book_model.dart
 
// กำหนดชื่อตารางไว้ในตัวแปร
final String tableBooks = 'books';

// กำหนดฟิลด์ข้อมูลของตาราง
class BookFields {
  // สร้างเป็นลิสรายการสำหรับคอลัมน์ฟิลด์
  static final List<String> values = [
    id, book_id, title, price, in_stock, num_pages, publication_date
  ];

  // กำหนดแต่ละฟิลด์ของตาราง ต้องเป็น String ทั้งหมด
  static final String id = '_id'; // ตัวแรกต้องเป็น _id ส่วนอื่นใช้ชื่อะไรก็ได้
  static final String book_id = 'book_id';
  static final String title = 'title';
  static final String price = 'price';
  static final String in_stock = 'in_stock';
  static final String num_pages = 'num_pages';
  static final String publication_date = 'publication_date';
}

// ส่วนของ Data Model ของหนังสือ
class Book {
  final int? id; // จะใช้ค่าจากที่ gen ในฐานข้อมูล
  final int book_id; 
  final String title;
  final double price;
  final bool in_stock;
  final int num_pages;
  final DateTime publication_date;

  // constructor
  const Book({
    this.id,
    required this.book_id,
    required this.title,
    required this.price,
    required this.in_stock,
    required this.num_pages,
    required this.publication_date,
  });

  // ฟังก์ชั่นสำหรับ สร้างข้อมูลใหม่ โดยรองรับแก้ไขเฉพาะฟิลด์ที่ต้องการ
  Book copy({
   int? id,
   int? book_id,
   String? title,
   double? price,
   bool? in_stock,
   int? num_pages,
   DateTime? publication_date,
  }) =>
    Book(
      id: id ?? this.id, 
      book_id: book_id ?? this.book_id,
      title: title ?? this.title,
      price: price ?? this.price,
      in_stock: in_stock ?? this.in_stock,
      num_pages: num_pages ?? this.num_pages,
      publication_date: publication_date ?? this.publication_date,
    );

  // สำหรับแปลงข้อมูลจาก Json เป็น Book object
  static Book fromJson(Map<String, Object?> json) =>  
    Book(
      id: json[BookFields.id] as int?,
      book_id: json[BookFields.book_id] as int,
      title: json[BookFields.title] as String,
      price: double.parse(json[BookFields.price] as String),
      in_stock: json[BookFields.in_stock] == 1,
      num_pages: json[BookFields.num_pages] as int,
      publication_date: DateTime.parse(json[BookFields.publication_date] as String),
    );

  // สำหรับแปลง Book object เป็น Json บันทึกลงฐานข้อมูล
  Map<String, Object?> toJson() => {
    BookFields.id: id,
    BookFields.book_id: book_id,    
    BookFields.title: title,
    BookFields.price: price,
    BookFields.in_stock: in_stock ? 1 : 0,
    BookFields.num_pages: num_pages,
    BookFields.publication_date: publication_date.toIso8601String(),
  };


}
 
    สังเกตการแปลงค่า DateTime , Boolean และ Double หากนำไปประยุกต์ใช้งาน ให้ใช้แนวทาง
ตามโค้ดตัวอย่าง ตัวอย่างเช่น boolean พอแปลงเป็นข้อมูล json จะไม่มีรูปแบบข้อมูลนี้ ดังนั้นจึง
ใช้เป็น 1 กับ 0  เช่นกับกับของวันที่ ก็แปลงเป็น string
 
BookFields.in_stock: in_stock ? 1 : 0,
BookFields.publication_date: publication_date.toIso8601String(),
 
    และเวลาแปลงกลับมาจาก json เป็น object ก็ต้องแปลงเป็นชนิดข้อมูลที่กำหนดด้วย
 
price: double.parse(json[BookFields.price] as String), // แปลงเป็น double
in_stock: json[BookFields.in_stock] == 1, // แปลงกลับเป็น boolean 
num_pages: json[BookFields.num_pages] as int,
publication_date: DateTime.parse(json[BookFields.publication_date] as String),
 
    การกำหนด id ควรกำหนดสองส่วน คือเพิ่มของ id ที่เป็นค่าจากฐานข้อมูลที่จะสร้างอัตโนมัติ
กับ id ของรายการนั้น เช่นในตัวอย่าง ก็จะมี id กับ book_id 
 
    รูปแบบการกำหนดของไฟล์ข้างต้น เวลานำไปประยุกต๋ก็แก้ไข และปรับให้เหมือนกับรูปแบบข้างต้น
มีส่วนต่างๆ ให้ครบถ้วน
 
 

    การใช้งาน Sqflite จัดการฐานข้อมูล

 
    ไฟล์ book_db.dart
 
import 'dart:async';

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

import '../models/book_model.dart';

// สร้าง class จัดการข้อมูล
class BooksDatabase {
  // กำหนดตัวแปรสำหรับอ้างอิงฐานข้อมูล
  static final BooksDatabase instance = BooksDatabase._init();

  // กำหนดตัวแปรฐานข้อมูล
  static Database? _database;

  BooksDatabase._init();

  Future<Database> get database async {
    // ถ้ามีฐานข้อมูลนี้แล้วคืนค่า 
    if (_database != null) return _database!;
    // ถ้ายังไม่มี สร้างฐานข้อมูล กำหนดชื่อ นามสกุล .db
    _database = await _initDB('books.db');
    // คืนค่าฐานข้อมูล
    return _database!;
  }

  // ฟังก์ชั่นสร้างฐานข้อมูล รับชื่อไฟล์ที่กำหนดเข้ามา
  Future<Database> _initDB(String filePath) async {
    // หาตำแหน่งที่จะจัดเก็บในระบบ ที่เตรียมไว้ให้
    final dbPath = await getDatabasesPath();
    // ต่อกับชื่อที่ส่งมา จะเป็น path เต็มของไฟล์
    final path = join(dbPath, filePath);
    // สร้างฐานข้อมูล และเปิดใช้งาน หากมีการแก้ไข ให้เปลี่ยนเลขเวอร์ชั่น เพิ่มขึ้นไปเรื่อยๆ
    return await openDatabase(path, version: 1, onCreate: _createDB);

  }

  // สร้างตาราง
   Future _createDB(Database db, int version) async {
     // รูปแบบข้อมูล sqlite ที่รองรับ
     final idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
     final textType = 'TEXT NOT NULL';
     final boolType = 'BOOLEAN NOT NULL';
     final integerType = 'INTEGER NOT NULL';

    // ทำคำสั่งสร้างตาราง
     await db.execute('''
CREATE TABLE $tableBooks (
  ${BookFields.id} $idType,
  ${BookFields.book_id} $integerType,
  ${BookFields.title} $textType,
  ${BookFields.price} $textType,
  ${BookFields.in_stock} $boolType,
  ${BookFields.num_pages} $integerType,
  ${BookFields.publication_date} $textType
)
''');
   } 

  // คำสั่งสำหรับเพิ่มข้อมูลใหม่ คืนค่าเป็น book object ที่เพิ่มไป
  Future<Book> create(Book book) async {
    final db = await instance.database; // อ้างอิงฐานข้อมูล

    final id = await db.insert(tableBooks, book.toJson());
    return book.copy(id: id);
  }

  // คำสั่งสำหรับแสดงข้อมูลหนังสือตามค่า id ที่ส่งมา
  Future<Book> readBook(int id) async {
    final db = await instance.database; // อ้างอิงฐานข้อมูล

    // ทำคำสั่งคิวรี่ข้อมูลตามเงื่อนไข 
    final maps = await db.query(
      tableBooks,
      columns: BookFields.values,
      where: '${BookFields.id} = ?',
      whereArgs: [id],
    );

    // ถ้ามีข้อมูล แสดงข้อมูลกลับออกไป
    if (maps.isNotEmpty) {
      return Book.fromJson(maps.first);
    } else { // ถ้าไม่มีแสดง error 
      throw Exception('ID $id not found');
    }
  }  

  // คำสั่งแสดงรายการหนึงสือทั้งหมด ต้องส่งกลับเป็น List
  Future<List<Book>> readAllBook() async {
    final db = await instance.database; // อ้างอิงฐานข้อมูล

    // กำหนดเงื่อนไขต่างๆ รองรับเงื่อนไขและรูปแบบของคำสั่ง sql ตัวอย่าง
    // ใช้แค่การจัดเรียงข้อมูล
    final orderBy = '${BookFields.id} DESC';
    final result = await db.query(tableBooks, orderBy: orderBy);

    // ข้อมูลในฐานข้อมูลปกติเป็น json string data เวลาสั่งค่ากลับต้องทำการ
    // แปลงข้อมูล จาก json ไปเป็น object กรณีแสดงหลายรายการก็ทำเป็น List
    return result.map((json) => Book.fromJson(json)).toList();
  }  

  // คำสังสำหรับอัพเดทข้อมููล ส่ง book object ที่จะอัพเดทเข้ามา
  Future<int> update(Book book) async {
    final db = await instance.database; // อ้างอิงฐานข้อมูล

    // คืนค่าเป็นตัวเลขจำนวนรายการที่มีการเปลี่ยนแปลง
    return db.update(
      tableBooks, 
      book.toJson(),
      where: '${BookFields.id} = ?',
      whereArgs: [book.id],      
    );

  }

  // คำสั่งสำหรับลบข้อมล รับค่า id ที่จะลบ
  Future<int> delete(int id) async {
    final db = await instance.database; // อ้างอิงฐานข้อมูล

    // คืนค่าเป็นตัวเลขจำนวนรายการที่มีการเปลี่ยนแปลง
    return db.delete(
      tableBooks, 
      where: '${BookFields.id} = ?',
      whereArgs: [id],      
    );

  }

  // คำสั่งสำหรับลบข้อมูลทั้งหมด
  Future<int> deleteAll() async {
    final db = await instance.database; // อ้างอิงฐานข้อมูล
    // คืนค่าเป็นตัวเลขจำนวนรายการที่มีการเปลี่ยนแปลง
    return db.delete(
      tableBooks,
    );

  }  

  // คำสั่งสำหรับปิดฐานข้อมูล เท่าที่ลองใช้ เราไม่ควรปิด หรือใช้คำสั่งนี้
  // เหมือนจะเป็น bug เพราะถ้าปิดฐานข้อมูล จะอ้างอิงไม่ค่อยได้ ในตัวอย่าง
  // จะไม่ปิดหรือใช้คำสั่งนี้
   Future close() async {
     final db = await instance.database; // อ้างอิงฐานข้อมูล

     db.close();
   }

}
 
    ในไฟล์นี้ จะเป็นการทำงานของฝั่งฐานข้อมูลทั้งหมด สามารถปรับประยุกต์ จากตัวอย่างได้เลย
เพราะรองรับการเพิ่ม ลบ แก้ไขรายการ ในกรณีแสดงทั้งหมด สามารถเลือกกำหนดจำนวน เงื่อนไข
จัดกลุ่ม เหล่านี้เพิ่มเติมได้ เช่น
 
final orderBy = '${BookFields.id} DESC';
final result = await db.query(tableBooks, 
    orderBy: orderBy,
    where: 'xxxx', // กำหนด string คำสั่งตามต้องการ
    groupBy: 'xxxx', // กำหนด string คำสั่งตามต้องการ
    offset: 0,
    limit: 10,
);
 
 
 

การประยุกต์ใช้งาน Sqflite

     มาถึงส่วนของการประยุกต์ใช้งาน หรือการนำ คำสั่งที่จัดการกับฐานข้อมูลมาใช้งานหน้า app ที่ต้องการ
ในที่นี้เราใช้ในไฟล์ชื่อ book.dart 
 
    ไฟล์ book.dart
 
import 'dart:async';
 
import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl.dart';
 
import '../db/book_db.dart';
import '../models/book_model.dart';
   
class Books extends StatefulWidget {
    static const routeName = '/book';
  
    const Books({Key? key}) : super(key: key);
   
    @override
    State<StatefulWidget> createState() {
        return _BooksState();
    }
}
   
class _BooksState extends State<Books> {
    late BooksDatabase _db; // อ้างอิงฐานข้อมูล
    late Future<List<Book>> books; // ลิสรายการหนังสือ
    int i = 0; // จำลองตัวเลขการเพิ่่มจำนวน
    late DateFormat dateFormat; // รูปแบบการจัดการวันที่และเวลา
 
    @override
    void initState() {
      // กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ
      Intl.defaultLocale = 'th';
      initializeDateFormatting();
      dateFormat = DateFormat.yMMMMEEEEd('th');
 
      // อ้างอิงฐานข้อมูล
      _db = BooksDatabase.instance;
      books = _db.readAllBook(); // แสดงรายการหนังสือ
      super.initState();
    }
 
    // คำสั่งลบรายการทั้งหมด
    Future<void> clearBook() async {
      await _db.deleteAll(); // ทำคำสั่งลบข้อมูลทั้งหมด
      setState(() {
        books = _db.readAllBook(); // แสดงรายการหนังสือ
      });      
    }
 
    // คำสั่งลบเฉพาะรายการที่กำหนดด้วย id ที่ต้องการ
    Future<void> deleteBook(int id) async {
      await _db.delete(id); // ทำคำสั่งลบข้มูลตามเงื่อนไข id
      setState(() {
        books = _db.readAllBook(); // แสดงรายการหนังสือ
      });    
    }
 
    // จำลองทำคำสั่งแก้ไขรายการ
    Future<void> editBook(Book book) async {
      // เลื่อกเปลี่ยนเฉพาะส่วนที่ต้องการ โดยใช้คำสั่ง copy
      book = book.copy(
        title: book.title+' new ',
        price: 30.00,
        in_stock: true,
        num_pages: 300,
        publication_date: DateTime.now()
      );      
      await _db.update(book); // ทำคำสั่งอัพเดทข้อมูล
      setState(() {
        books = _db.readAllBook(); // แสดงรายการหนังสือ
      });    
    }    
 
    // จำลองทำคำสั่งเพิ่มข้อมูลใหม่
    Future<void> newBook() async {
      i++;
      Book book = Book(
        book_id: i,
        title: 'Book title $i',
        price: 20.00,
        in_stock: true,
        num_pages: 200,
        publication_date: DateTime.now()
      );
      await _db.create(book); // ทำคำสั่งเพิ่มข้อมูลใหม่
      setState(() {
        books = _db.readAllBook(); // แสดงรายการหนังสือ
      });
    }
 
    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Book'),
                actions: <Widget>[ // 
                  IconButton(
                    onPressed: () => clearBook(), // ปุ่มลบข้อมูลทั้งหมด
                    icon: const Icon(Icons.clear_all),
                  ),
                ],
            ),
            body: Center(
              child: FutureBuilder<List<Book>>( // ชนิดของข้อมูล
                future: books, // ข้อมูล Future
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                      return Column(
                          children: [
                            Expanded( // ส่วนของลิสรายการ
                                child: snapshot.data!.isNotEmpty // กำหนดเงื่อนไขตรงนี้
                                ? ListView.separated( // กรณีมีรายการ แสดงปกติหนด controller ที่จะใช้งานร่วม
                                        itemCount: snapshot.data!.length,
                                        itemBuilder: (context, index) {
                                          Book book = snapshot.data![index];
 
                                          Widget card; // สร้างเป็นตัวแปร
                                          card = Card(
                                            margin: const EdgeInsets.all(5.0), // การเยื้องขอบ
                                            child: Column(
                                              children: [
                                                ListTile(
                                                  leading: IconButton(
                                                    onPressed: () => editBook(book), // จำลองแก้ไขข้อมูล
                                                    icon: const Icon(Icons.edit),
                                                  ),
                                                  title: Text(book.title),
                                                  subtitle: Text('Date: ${dateFormat.format(book.publication_date)}'),
                                                  trailing: IconButton(
                                                    onPressed: () => deleteBook(book.id!), // ลบข้อมูล
                                                    icon: const Icon(Icons.delete),
                                                  ),
                                                  onTap: (){
                                                     _viewDetail(book.id!); // กดเลือกรายการให้แสดงรายละเอียด                                           
                                                  },
                                                ),
                                              ],
                                            )
                                          );
                                          return card;
                                        },
                                        separatorBuilder: (BuildContext context, int index) => const SizedBox(),
                                )
                                : const Center(child: Text('No items')), // กรณีไม่มีรายการ
                            ),
                          ],
                        );
                  } else if (snapshot.hasError) { // กรณี error
                    return Text('${snapshot.error}');
                  }
                  // กรณีสถานะเป็น waiting ยังไม่มีข้อมูล แสดงตัว loading
                 return const RefreshProgressIndicator();
                },
              ),  
            ),  
            floatingActionButton: FloatingActionButton(
              onPressed: () => newBook(),
              child: const Icon(Icons.add),
            ),
        );
    }
 
    // สร้างฟังก์ชั่นจำลองการแสดงรายละเอียดข้อมูล
    Future<Widget?> _viewDetail(int id) async {
      Future<Book> book = _db.readBook(id); // ดึงข้อมูลจากฐานข้อมูลมาแสดง
      showModalBottomSheet(
        context: context,
        builder: (BuildContext context){
            return FutureBuilder<Book>(
              future: book,
              builder: (context,snapshot){
                if (snapshot.hasData) {
                  var book = snapshot.data!;
                  return Container(
                    width: MediaQuery.of(context).size.width,
                    height: 200,
                    padding: const EdgeInsets.all(10.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text('ID: ${book.id}'),
                        SizedBox(height: 5,),
                        Text('ชื่อหนังสือ: ${book.title}'),
                        SizedBox(height: 5,),
                        Text('รหัส: ${book.book_id}'),
                        SizedBox(height: 5,),
                        Text('ราคา: ${book.price}'),
                        SizedBox(height: 5,),
                        Text('จำนวนหน้า: ${book.num_pages}'),
                        SizedBox(height: 5,),
                        Text('มีในคลัง: ${ book.in_stock ? 'มี' : 'ไม่มี'}'),
                        SizedBox(height: 5,),
                        Text('วันที่: ${dateFormat.format(book.publication_date)}'),
                      ],
                    ),
                  );
                } else if (snapshot.hasError) { // กรณี error
                  return Text('${snapshot.error}');
                }
                return const RefreshProgressIndicator();
              }
            );
        }
      );
      return null;
    }
 
}
 
    เพิ่มปุ่มลิ้งค์มาหน้า book ในไฟล์ about.dart
มีสองส่วนคือ import book.dart

import './book.dart'; 


และ ส่วนของการกำหนดปุ่ม

ElevatedButton(
  onPressed: () {
	/* Navigator.pushNamed(
		context,
		Books.routeName
	); */
	Navigator.push(
	  context, 
	  MaterialPageRoute(builder: (context) => Books()),
	);                              
  },
  child: Text('Go to Book'),
),   
 
    ในตัวอย่าง เรามีการใช้งานฐานข้อมูล จากไฟล์ book_db.dart ที่มีคำสั่งต่างๆ ที่เรากำหนดไว้แล้ว
โดยกำหนดตัวแปรชื่อ _db = BooksDatabase.instance; สำหรับอ้างอิงฐานข้อมูล สำหรับขอมูลที่ได้
จากการแสดงรายการทั้งหมด หรือแสดงบางรายการตาม id ที่กำหนด จะเป็นข้อมูล Future เวลาแสดง
เราจึงใช้ FutureBuilder มาใช้งานร่วมด้วย
    เมื่อเริ่มทำงาน เราจะทำการไปอ่านข้อมูลจากฐานข้อมูล ว่ามีรายการหนังสืออยู่หรือไม่ ถ้ามีก็คืนค่า
กลับมาใช้งาน ถ้าไม่มีก็แสดงข้อความ 'No items'
    เราจำลองเมื่อกดปุ่มเครื่องหมายบวก + ก็ให้ทำการเพิ่มข้อมูลลงในฐานข้อมูล หลังจากเพิ่มก็อัพเดท
รายการข้อมูล ก็จะเห็นว่ามีรายการใหม่เพิ่มเข้ามาด้านบน
    เมื่อกดที่รายการใดๆ ก็จะไปดึงข้อมูลจากฐานข้อมูล ของรายการนั้นๆ มาแสดง จริงๆ ถ้าข้อมูลใน
snapshot มีข้อมูลทั้งหมดแล้ว เราไม่จำเป็นต้องไปดึงจากฐานข้อมูลก็ได้ สามารถส่งค่ามาแสดงได้เลย
แต่ในที่นี้ เราจำลองสมมติว่า ต้องการไปดึงข้อมูลทั้งหมดจากฐานข้อมูลมาแสดงแทนการส่งค่า
    เราสามารถลบราายการทั้งหมด โดยคลิกที่ปุ่ม action มุมบนขวา
    การลบ และแก้ไขแต่ละรายการ สามารถกดที่ไอคอน ด้านหน้า และด้านหลังแต่ละรายการตามลำดับ
 
 

การจัดรูปแบบวันที่ด้วย intl package

    เราสามารถจัดรูปแบบการแสดงข้อมูลวันที่หรือ DateTime ด้วย package ชื่อ intl ที่ได้ติดตั้งไปตอนต้น
ซึ่งรองรับการกำหนดและแสดงเป็นภาษาไทย มีรูปแบบการใช้งานไม่ยุ่งยาก
 
    ตัวอย่างการกำหนดรูปแบบโดยใช้ค่าคงที่
 
DateFormat.MMMM('th'),			: พฤศจิกายน 
DateFormat.MMMMd('th'),		  : 6 พฤศจิกายน 
DateFormat.MMMMEEEEd('th'),	: วันเสาร์ที่ 6 พฤศจิกายน 
DateFormat.M('th'),				  : 11 
DateFormat.Md('th'),				: 6/11 
DateFormat.MEd('th'),			  : ส. 6/11 
DateFormat.s('th'),				  : 16 
DateFormat.LLLL('th'),			: พฤศจิกายน 
DateFormat.EEEE('th'),			: วันเสาร์ 
DateFormat.y('th'),				  : 2021 
DateFormat.yMMM('th'),			: พ.ย. 2021 
DateFormat.yMMMd('th'),		  : 6 พ.ย. 2021 
DateFormat.yMMMEd('th'),		: ส. 6 พ.ย. 2021 
DateFormat.yQQQ('th'),			: ไตรมาส 4 2021 
DateFormat.yMMMM('th'),		    : พฤศจิกายน ค.ศ. 2021 
DateFormat.yMMMMEEEEd('th'),	: วันเสาร์ที่ 6 พฤศจิกายน ค.ศ. 2021 
DateFormat.yMMMMd('th'),	    : 6 พฤศจิกายน ค.ศ. 2021 
DateFormat.yM('th'),			: 11/2021 
DateFormat.yMd('th'),			: 6/11/2021 
DateFormat.yMEd('th'),		: ส. 6/11/2021 
DateFormat.yQQQQ('th'),		: ไตรมาส 4 ค.ศ. 2021 
DateFormat.MMM('th'),			: พ.ย.
DateFormat.MMMd('th'),		: 6 พ.ย.
DateFormat.MMMEd('th'),		: ส. 6 พ.ย.
DateFormat.QQQ('th'),			: ไตรมาส 4
DateFormat.LLL('th'),			: พ.ย.
DateFormat.E('th'),				: ส.
DateFormat.d('th'),				: 6
DateFormat.m('th'),				: 52 
DateFormat.ms('th'),			: 52:16 
DateFormat.j('th'),				: 17
DateFormat.H('th'),				: 17
DateFormat.Hm('th'),			: 17:45 น.
DateFormat.Hms('th'),			: 17:45:10
DateFormat.jm('th'),			: 17:49 น.
DateFormat.jms('th'),			: 17:49:25
 
    ตัวอย่างเช่น เรากำหนดเป็น
 
// กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ
Intl.defaultLocale = 'th';
initializeDateFormatting();
dateFormat = DateFormat.yMMMd('th');
 
    ผลลัพธ์ที่ได้
 
 



 
    หรือกรณีเราต้องการรูปแบบที่มีข้อความกำหนดเอง เช่น
 
// กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ
Intl.defaultLocale = 'th';
initializeDateFormatting();
// dateFormat = DateFormat.yMMMd('th');
dateFormat = DateFormat('วันที่ d เดือน MMM ปี y','th');
 
    จะได้เป็น
 
 

 
 
 
    หวังว่าเนื้อหาตอนนี้ จะสามารถเป็นแนวทางนำไปปรับใช้งาน เช่น ต้องการให้ app สามารถทำงาน
ออฟไลน์ได้ โดยบันทึกลงในฐานข้อมูลไว้ และเมื่ออนไลน์หรือเชื่อมต่ออินเตอร์เน็ตก็สามารถ sync ข้อมูล
ขึ้นไปเก็บบน server ได้  หรือจะใช้เก็บข้อมูล cache เช่น ดึงข้อมูลจาก server กรณีที่ออนไลน์อยู่ มาเก็บ
บันทึกในฐานข้อมูล เมื่อออฟไลน์ก็ใช้ข้อมูลในฐานข้อมูลที่เครื่อง แบบนี้เป็นต้น
    เนื้อหาตอนหน้าเป็นอะไร รอติดตาม


   เพิ่มเติมเนื้อหา ครั้งที่ 1 วันที่ 29-07-2024


ดาวน์โหลดโค้ดตัวอย่าง สามารถนำไปประยุกต์ หรือ run ทดสอบได้

http://niik.in/download/flutter/demo_021_29072024_source.rar


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



อ่านต่อที่บทความ



ทบทวนบทความที่แล้ว









เนื้อหาที่เกี่ยวข้อง






เนื้อหาพิเศษ เฉพาะสำหรับสมาชิก

กรุณาล็อกอิน เพื่ออ่านเนื้อหาบทความ

ยังไม่เป็นสมาชิก

สมาชิกล็อกอิน



( หรือ เข้าใช้งานผ่าน Social Login )




URL สำหรับอ้างอิง





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ