การจัดการข้อมูลของ Form Element อื่นๆ ใน Flutter

เขียนเมื่อ 3 ปีก่อน โดย Ninenik Narkdee
checkboxlisttile radiolisttile dropdownbuttonformfield flutter

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ checkboxlisttile radiolisttile dropdownbuttonformfield flutter

ดูแล้ว 5,415 ครั้ง




เนื้อหาต่อไปนี้ จะมาดูต่อเกี่ยวกับการใช้งานฟอร์ม ต่อจาก
เนื้อหาตอนที่แล้ว ที่เราพูดถึงเกี่ยวกับการใช้งาน TextFormField
เป็นส่วนใหญ่ ยังมี widget เพิ่มเติมที่ใช้งามร่วมกับฟอร์ม รวมไปถึง
การจัดการกับข้อมูลที่ได้จากฟอร์ม เพื่อนำไปใช้งานต่อ
ทบทวนตอนที่แล้วได้ที่บทความ
    การใช้งาน Form และ Form Validation ใน Flutter http://niik.in/1048
 
   *เนื้อหานี้ใช้เนื้อหาต่อเนื่องจากบทความ http://niik.in/1048
 
 

การใช้งาน Checkbox

    เราสามารถกำหนด checkbox ให้กับฟอร์มด้วย 2 widget คือ Checkbox กับ CheckboxListTile
แต่เราจะแนะนำเป็น CheckboxListTile() ที่จะใช้งานได้งายและสะดวกกว่า เพราะเป็นการนำเอา ListTile กับ
Checkbox มารวมกัน สามารถกดที่พื้นที่ของ ListTile หรือข้อความแทนการกดที่ตัว checkbox โดยตรง
สามารถจัดตำแหน่งไม่ว่าจะไว้ด้านหน้าข้อความ หรือด้านหลังข้อความก็ทำได้ง่าย
 
กำหนด State property ที่เกี่ยวข้อง
1
bool _termsChecked = false;
 
    ดูตัวอย่างการใช้งาน checkbox ทั้งสองแบบ
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ListTile(
  title: Text('This is title'),
  trailing: Checkbox(
  value: _termsChecked,
  onChanged: (bool? value) {
    setState(() {
      _termsChecked = value!;
    });
  },
),
),
CheckboxListTile(
  value: _termsChecked,
  onChanged: (value) {
    setState(() {
      _termsChecked = value!;
    });
  },
  subtitle: !_termsChecked
      ? Text(
          'Required',
          style: TextStyle(color: Colors.red, fontSize: 12.0),
        )
      : null,
  title: new Text(
    'I agree to the terms and condition',
  ),
  controlAffinity: ListTileControlAffinity.leading,
),
 
ผลลัพธ์ที่ได้
 


 
 
    ตัวแรกเราต้องจัดรูปแบบใน ListTile อีกที แต่ตัวที่สองเราสามารถใช้งานคล้าย ListTile ได้เลย
    ในที่นี้จะพูดถึง CheckboxListTile
    ตัว checkbox จะรองรับค่าหรือ value ที่เป็น boolean เวลาเราจะใช้งาน ต้องกำหนดตัวแปร boolean
เพื่อรับค่ามาใช้งาน  ใช้สำหรับตอบรับ หรือปฏิเสธในกรณีเงื่อนไขให้เลือก 1 รายการ อย่างในตัวอย่าง 
เป็นการให้เลือก ตอบรับ ข้อกำหนดของการใช้งาน
    ในกรณีใช้เป็นตัวเลือกหลายๆ รายการ จะหมายถึง ตอบรับกับรายการตัวเลือกนั้นๆ หรือไม่ ดูตัวอย่าง
 
1
2
3
4
5
6
7
8
9
10
// กำหนดตัวแปร ลิสรายการ checkbox
List<Map<String, bool>> hobbies = [
  {'อ่านหนังสือ': true},
  {'วาดรูป': false},
  {'ดูหนัง': true},
  {'ช้อปปิ้ง': true},
];
 
// กำหนดตัวแปร เก็บค่าของแต่ละ checkbxo
List<bool> _checkHobby = [];
 
    ต่อไปส่วนของการวนลูปแสดงข้อมูล และใช้งาน
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Divider(), // ตัว widget แบ่ง
Builder(builder: (context) { // เราใช้ Builder เพื่อที่จะใช้งานฟังก์ชั่นสร้าง widget ได้
  List<Widget> list = <Widget>[];
  hobbies.asMap().forEach((index, hobby){ // วนลูปสร้างลิสรายการ
    var key = hobby.keys.toList(); // แปลงเป็น list ของ key
    var val = hobby.values.toList();  // แปลงเป็น list ของ value  
    _checkHobby.add(val[0]); // เก็บค่า value ขแงแต่ละรายการ
    list.add(CheckboxListTile(
      value: _checkHobby[index], // ใช้ค่า value ของแต่ละรายการ
      onChanged: (value) {
        setState(() {
          _checkHobby[index] = value!; // เปลี่ยนค่าเมื่อมีการเลือกหรือไม่เลือก
        });
      },
      title:  Text( '${key[0]}', ),
      controlAffinity: ListTileControlAffinity.leading,
    ));
  });
  return Column( // คืนค่าเป็นรายการ checkbox ในคอลัมน์
    children: list,
  );
}),
 
    ผลลัพธ์ที่ได้
 


 
 
    กรณีมีตัวเลือกหลายรายการ จะเป็นลักษณะ ว่าแต่ละรายการเราเลือกหรือไม่
 
 
 

การใช้งาน Radio

    รูปแบบการใช้งาน radio ร่วมกับฟอร์ม ก็สามารถทำได้คล้ายๆ กับ checkbox โดยเราสามารถใช้ได้ทั้ง
Radio กับ RadioListTile และวิธีการที่สะดวกและง่ายก็แนะนำเป็น RadioListTile 
    radio จะใช้สำหรับให้เลือกอย่างใดอย่างหนึ่งเพียงอย่างเดียว จากรายการที่แสดงให้เลือก โดยค่าที่กำหนดให้
กับ radio จะเป็น object แตกต่างจาก checkbox ซึ่ง object หรือ class ที่เหมาะจะมาใช้เป็นข้อมูล radio ก็คือ
enum ( มีอธิบายไว้ในบทความ http://niik.in/1044 )
    อย่างสมมติเช่น เรากำหนดสีตัวเลือก ให้ผู้ใช้ระบุ ก็จะกำหนดเป็น
 
1
enum ColorOption { red, green, blue }
 
    อย่าลืมว่า enum เป็น class หนึ่ง ดังนั้นเวลาระบุ ก็ต้องกำหนดไว้ด้านนอกของ class อื่นๆ
 
    ปกติจะใช้ radio ในการกำหนดตัวเลือกที่ไม่มากนัก  ดูตัวอย่าง การเลือกเพศ ชาย หญิง
    สิ่งแรกก็คือกำหนด class หรือ object ของค่าข้อมูลที่จะใช้งาน
 
1
enum Gender { male, female }
 
    จากนั้นเราก็กำหนดตัวแปรค่าเริ่มต้น
 
1
2
3
4
// กำหนดตัวแปรค่าเริ่มต้นของรายการที่่ถูกเลือก
Gender? _selectedGender = Gender.male;
// กำหนดตัวแปรสำหรับใช้เก็บข้อความอ้างอิง
String? _selectedGenderText = 'ชาย';
 
    เรากำหนดตัวแปรค่าเริ่มต้นสำหรับรายการที่ถูกเลือก และกำหนดตัวแปร
ข้อมูลเพิ่มเติม สำหรับนำไปใช้งาน อย่างข้างต้น ให้ค่าเริ่มต้นเป็น male และข้อความ
ที่สัมพันธ์ก็คือ เพศ 'ชาย'
 
    ตัวอย่างการเรียกใช้งาน RadioListTile
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Column(
  children: <Widget>[
    RadioListTile(
      title: const Text('Male'),
      value: Gender.male, // ค่าของตัวเล็อก male
      groupValue: _selectedGender, // ใช้กลุ่มค่าที่ถูกเลือกเป็นตัวแปรเดียวกัน
      onChanged: (Gender? value) {
        setState(() {
          _selectedGender = value;
          _selectedGenderText =  (_selectedGender == Gender.male) ? 'ชาย' : 'หญิง';
        });
      },
      controlAffinity: ListTileControlAffinity.leading,
    ),
    RadioListTile(
      title: const Text('Female'),
      value: Gender.female, // ค่าของตัวเล็อก female
      groupValue: _selectedGender, // ใช้กลุ่มค่าที่ถูกเลือกเป็นตัวแปรเดียวกัน
      onChanged: (Gender? value) {
        setState(() {
          _selectedGender = value;
          _selectedGenderText =  (_selectedGender == Gender.male) ? 'ชาย' : 'หญิง';
        });
      },
      controlAffinity: ListTileControlAffinity.leading,
    ),
  ],
),
 
    ผลลัพธ์ที่ได้
 


 
 
    ค่าเริ่มต้นที่ถูกเลือกเป็น male เมื่อเรากดปุ่ม submit ก็จะแสดงในส่วนของข้อความที่เรากำหนดไว้ใช้งาน
ให้สัมพันธ์กับข้อมูลที่เลือก
 
    สมมติเราอยากสร้างรายการ radio รองรับจำนวนมากขึ้นมาหน่อย ก็สามารถใช้เป็นแบบนี้ได้ 
 
1
enum ColorOption { red, green, blue }
 
    จากนั้นเราก็กำหนดตัวแปรค่าเริ่มต้น
 
1
2
3
4
5
6
// กำหนดตัวแปรค่าเริ่มต้นของรายการที่่ถูกเลือก
ColorOption? _selectedColorOption = ColorOption.red;
// กำหนดตัวแปรสำหรับใช้เก็บข้อความอ้างอิง
String _selectedColorOptionText = 'สีแดง';
// กำหนดตัวแปรสำหรับใช้เก็บข้อความอ้างอิงในลูป
List<String> _listColorOptionText = ['สีแดง', 'สีเขียว', 'สีน้ำเงิน'];
 
    ตัวอย่างการเรียกใช้งาน RadioListTile
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Divider(),
Builder(builder: (context) {
  List<Widget> list = <Widget>[];
  ColorOption.values.asMap().forEach((index, val){
    list.add(
      RadioListTile(
        title: Text(_listColorOptionText[index]),
        value: val, // ค่าของตัวเล็อก female
        groupValue: _selectedColorOption, // ใช้กลุ่มค่าที่ถูกเลือกเป็นตัวแปรเดียวกัน
        onChanged: (ColorOption? value) {
          setState(() {
            _selectedColorOption = value;
            _selectedColorOptionText = _listColorOptionText[index];
          });
        },
        controlAffinity: ListTileControlAffinity.leading,
      ),
    );
  });
  return Column(
    children: list,
  );
}),
 
    ผลลัพธ์ที่ได้
 


 
 
    วิธีนี้เหมาะกับรายการตัวเลือกที่มีจำนวนมากๆ เวลากำหนดก็จะทำได้ง่ายขึ้น กว่าการเพิ่มทีละตัว
 
 
 

การใช้งาน Dropdown

    ใช้สำหรับแสดงลิสรายการเพื่อให้ผู้ใช้เลือกหรือกำหนดค่าที่ต้องการ คล้ายกับการเลือกของ radio ที่จะ
สามารถเลือกได้เพียงอันเดียว จากรายการทั้งหมด การใช้งาน DropdownButtonFormField จะรองรับสำหรับ
ฟอร์มมากกว่าการใช้งาน DropdownButton ธรรมดา ดูตัวอย่างทั้งสองรูปแบบ เบื้องต้น
 
กำหนด State property ที่เกี่ยวข้อง
1
String _dropdownValue = '';
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
DropdownButton<String>(
  value: null,
  onChanged: (String? newValue) {
    setState(() {
      _dropdownValue = newValue!;
    });
  },
  isExpanded: true,
  items: <String>['One', 'Two', 'Three', 'Four']
      .map<DropdownMenuItem<String>>((String value) {
    return DropdownMenuItem<String>(
      value: value,
      child: Text(value),
    );
  }).toList(),
),                     
SizedBox(height: 5.0,),
DropdownButtonFormField<String>(
  value: null,
  onChanged: (value) {
    setState(() {
      _dropdownValue = value!;
    });
  },
  hint: Text('Rating'),
  isExpanded: true
  items: <String>['One', 'Two', 'Three', 'Four']
      .map<DropdownMenuItem<String>>((String value) {
    return DropdownMenuItem<String>(
      value: value,
      child: Text(value),
    );
  }).toList(), 
),
 
    ผลลัพธ์ที่ได้
 


 
 
    มาดูวิธีการกำหนดและใช้งานสำหรับฟอร์ม 
 
1
2
3
4
// กำหนดตัวแปรสำหรับลิสรายการ
List<String> maritalStatus = ['โสด','แต่งงาน','หย่า','หม้าย'];
// กำหนดตัวแปรสำหรับเก็บค่าที่เลือก เริ่มต้นเป็นค่าว่าง
String _seslectedMaritalStatus = '';
 
     ต่อไปเรียกใช้งานเป็นดังนี้
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Divider(),
DropdownButtonFormField<String>(
  value: null,
  autovalidateMode: AutovalidateMode.always,
//  validator: (value) => (value == null) ? 'เลือกสถานะการแต่งงาน' : null,
  validator: Validators.required('เลือกสถานะการแต่งงาน'),
  onChanged: (value) {
    setState(() {
      _seslectedMaritalStatus = value!;
    });
  },
  hint: Text('สถานะการแต่งงาน'),
  isExpanded: true
  items: maritalStatus.map<DropdownMenuItem<String>>((String value) {
    return DropdownMenuItem<String>(
      value: value,
      child: Text(value),
    );
  }).toList(), 
),
 
    ผลลัพธ์ที่ได้
 


 
 
    จะเห็นว่า DropdownButtonFormField รองรับการตรวจสอบข้อมูลด้วย validator เหมือนกับ TextFormField
เราสามารถสร้าง List<String> เพื่อวนลูปสร้างรายการตัวเลือกให้กับ dropbox ได้ง่าย
 
 
    ตอนนี้เราได้รู้จัก element ที่ใช้งานร่วมกับฟอร์มเพิ่มเติม รวมถึง TextFormFiled จากบทความตอนที่แล้ว เราได้
รู้จักวิธีการสร้างลิสรายการสำหรับแต่ละ widget  รู้จักกำหนดตัวแปรสำหรับรับค่าเพื่อนำไปใช้งานต่อ 
    เราจะลองสร้างฟอร์มสมมติ โดยรวม element ต่างๆ มาไว้ด้วยกันในฟอร์ม ตามตัวอย่างข้างล่าง และรูปแบบการ
กำหนดสำหรับเป็นข้อมูลของฟอร์ม เมื่อกดส่งข้อมูล จะจำลองการแสดงข้อมูลที่เป็น Map 
 

    ไฟล์ contact.dart

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl.dart';
import 'package:flutter/services.dart';
  
import '../validations/validation.dart';
  
    
class Contact extends StatefulWidget {
    static const routeName = '/contact';
   
    const Contact({Key? key}) : super(key: key);
    
    @override
    State<StatefulWidget> createState() {
        return _ContactState();
    }
}
    
class _ContactState extends State<Contact> with Validators {
  
    // กำหนดข้อมูลฟิลด์ สำหรับบันทึก
    final Map<String, dynamic> formData = {
        'email': null,
        'password': null,
        'birthday': null,
        'gender': null,
        'hobby': null,
        'maritalstatus': null,
      };
  
    
    // สร้างฟอร์ม key หรือ id ของฟอร์มสำหรับอ้างอิง
    final _formKey = GlobalKey<FormState>();
  
    late DateFormat dateFormat; // รูปแบบการจัดการวันที่และเวลา
  
    // กำหนดตัวแปรรับค่า
    final _text1 = TextEditingController();
    final _text2 = TextEditingController();
    final _text3 = TextEditingController();
    final _text4 = TextEditingController();   
  
    // กำหนดตัวแปร ลิสรายการ checkbox
    List<Map<String, bool>> hobbies = [
      {'อ่านหนังสือ': true},
      {'วาดรูป': false},
      {'ดูหนัง': true},
      {'ช้อปปิ้ง': true},
    ];
    // กำหนดตัวแปร เก็บค่าของแต่ละ checkbxo
    List<bool> _checkHobby = [];
    List<String> _checkedHobby = []; // ค่าสำหรับส่งไปใช้งาน
  
    // กำหนดตัวแปรค่าเริ่มต้นของรายการที่่ถูกเลือก
    Gender? _selectedGender = Gender.male;
    // กำหนดตัวแปรสำหรับใช้เก็บข้อความอ้างอิง
    String? _selectedGenderText = 'ชาย';
    // กำหนดตัวแปรสำหรับใช้เก็บข้อความอ้างอิงในลูป
    List<String> _listGenderText = ['ชาย', 'หญิง'];
  
  
    // กำหนดตัวแปรสำหรับลิสรายการ
    List<String> maritalStatus = ['โสด','แต่งงาน','หย่า','หม้าย'];
    // กำหนดตัวแปรสำหรับเก็บค่าที่เลือก เริ่มต้นเป็นค่าว่าง
    String _seslectedMaritalStatus = '';
  
    // กำหนดสถานะการแสดงแบบรหัสผ่าน
    bool _isHidden = true;
    bool _termsChecked = false;
  
  
    void _selectDate() async {
       
      final DateTime now = DateTime.now();
      final DateTime firstDate = DateTime(2017, 7, 1); //  ช่วงเริ่มต้น
      final DateTime lastDate = DateTime(2023, 7, 1); //  ช่วงสิ้นสิน
      final DateTime initialDate = now.isAfter(lastDate) ? lastDate : now;
 
      final DateTime? newDate = await showDatePicker(
        context: context,
        initialDate: initialDate,
        firstDate: firstDate,
        lastDate: lastDate,
        helpText: 'Select a date',
      );
      if (newDate != null) {
        setState(() {
          _text2.value = TextEditingValue(text: dateFormat.format(newDate).toString());
        });
      }
    }   
  
    // เกียวกับการใช้เวลา
    /// แปลงเวลาจากวันที่ TimeOfDay.fromDateTime(DateTime.now())
    /// เวลาปัจจุบัน TimeOfDay.now()
    /// แบบกำหนดเอง TimeOfDay(hour: 7, minute: 15),
    void _selectTime() async {
      final TimeOfDay? newTime = await showTimePicker(
        context: context,
        initialTime: TimeOfDay.now(),
      );
      if (newTime != null) {
        setState(() {
          _text2.value = TextEditingValue(text: newTime.format(context));
        });
      }
    }   
  
    @override
    void initState() {
      super.initState();
      // กำหนดรูปแบบการจัดการวันที่และเวลา
      Intl.defaultLocale = 'en';
      initializeDateFormatting();
      dateFormat = DateFormat('d/MM/y','en');
  
    }
  
    @override
    void dispose() {
      _text1.dispose(); // ยกเลิกการใช้งานที่เกี่ยวข้องทั้งหมดถ้ามี
      _text2.dispose();
      _text3.dispose();
      _text4.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
          
        return Scaffold(
            appBar: AppBar(
                title: Text('Contact Us'),
            ),
            body: SingleChildScrollView(
              child: Form(  // ใช้งาน Form
                key: _formKey, // กำหนด key
                child: Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: Column(
                      children: <Widget>[ // กำหนด widget ที่จะใช้งานกับฟอร์ม
                        TextFormField(
                          autovalidateMode: AutovalidateMode.always,
                          decoration: InputDecoration(
                            hintText: 'อีเมล',   
                            icon: Icon(Icons.email_outlined),
                          ),
                          controller: _text1, // ผูกกับ TextFormField ที่จะใช้
                          validator: Validators.compose([
                            Validators.required('กรุณาระบุอีเมล'),
                            Validators.email('กรุณาใส่อีเมลให้ถูกต้อง')
                          ]),
                        ),
                        SizedBox(height: 5.0,),
                        TextFormField(
                          autovalidateMode: AutovalidateMode.always,
                          decoration: InputDecoration(
                            icon: Icon(Icons.vpn_key),
                            hintText: 'รหัสผ่าน',
                            suffixIcon: IconButton(
                              onPressed: (){
                                setState(() {
                                  _isHidden = !_isHidden; // เมื่อกดก็เปลี่ยนค่าตรงกันข้าม
                                });
                              },
                              icon: Icon(
                                _isHidden // เงื่อนไขการสลับ icon
                                ? Icons.visibility_off
                                : Icons.visibility
                              ),
                            ),
                          ),   
                          controller: _text3, // ผูกกับ TextFormField ที่จะใช้                       
                          validator: Validators.required('กรุณาระบุรห้สผ่าน'),
                          obscureText: _isHidden, // การซ่อนหรือแสดงข้อความในรูปแบบรหัสผ่าน
                        ),
                        SizedBox(height: 5.0,),
                        TextFormField(
                          autovalidateMode: AutovalidateMode.always, 
                          decoration: InputDecoration(
                            hintText: 'วันเกิด',
                            icon: Icon(Icons.date_range),
                          ),
                          controller: _text2, // ผูกกับ TextFormField ที่จะใช้
                          validator: Validators.required('กรุณาระบุวันเกิด'),
                          onTap: _selectDate,
                          readOnly: true,
                        ),
                        Divider(),
                        Builder(builder: (context) {
                          List<Widget> list = <Widget>[];
                          Gender.values.asMap().forEach((index, val){
                            list.add(
                              RadioListTile(
                                title: Text(_listGenderText[index]),
                                value: val, // ค่าของตัวเล็อก female
                                groupValue: _selectedGender, // ใช้กลุ่มค่าที่ถูกเลือกเป็นตัวแปรเดียวกัน
                                onChanged: (Gender? value) {
                                  setState(() {
                                    _selectedGender = value;
                                    _selectedGenderText = _listGenderText[index];
                                  });
                                },
                                controlAffinity: ListTileControlAffinity.leading,
                              ),
                            );
                          });
                          return Column(
                            children: list,
                          );
                        }),
                        Divider(), // ตัว widget แบ่ง
                        Builder(builder: (context) { // เราใช้ Builder เพื่อที่จะใช้งานฟังก์ชั่นสร้าง widget ได้
                          List<Widget> list = <Widget>[];
                          _checkedHobby.clear();
                          hobbies.asMap().forEach((index, hobby){ // วนลูปสร้างลิสรายการ
                            var key = hobby.keys.toList(); // แปลงเป็น list ของ key
                            var val = hobby.values.toList();  // แปลงเป็น list ของ value  
                            _checkHobby.add(val[0]); // เก็บค่า value ขแงแต่ละรายการ
                            if(_checkHobby[index]) _checkedHobby.add(key[0]); // เก็บรายการที่เลือก
                            list.add(CheckboxListTile(
                              value: _checkHobby[index], // ใช้ค่า value ของแต่ละรายการ
                              onChanged: (value) {
                                setState(() {
                                  _checkHobby[index] = value!; // เปลี่ยนค่าเมื่อมีการเลือกหรือไม่เลือก
                                });
                              },
                              title:  Text( '${key[0]}', ),
                              controlAffinity: ListTileControlAffinity.leading,
                            ));
                          });
                          return Column( // คืนค่าเป็นรายการ checkbox ในคอลัมน์
                            children: list,
                          );
                        }),
                        Divider(),
                        DropdownButtonFormField<String>(
                          value: null,
                          autovalidateMode: AutovalidateMode.always,
                          decoration: InputDecoration(
                            icon: Icon(Icons.family_restroom_outlined),
                          ),
                          validator: Validators.required('เลือกสถานะการแต่งงาน'),
                          onChanged: (value) {
                            setState(() {
                              _seslectedMaritalStatus = value!;
                            });
                          },
                          hint: Text('สถานะการแต่งงาน'),
                          isExpanded: true
                          items: maritalStatus.map<DropdownMenuItem<String>>((String value) {
                            return DropdownMenuItem<String>(
                              value: value,
                              child: Text(value),
                            );
                          }).toList(), 
                        ),
                        Divider(),
                        CheckboxListTile(
                          value: _termsChecked,
                          onChanged: (value) {
                            setState(() {
                              _termsChecked = value!;
                            });
                          },
                          subtitle: !_termsChecked
                              ? Text(
                                  'ต้องระบุ',
                                  style: TextStyle(color: Colors.red, fontSize: 12.0),
                                )
                              : null,
                          title: new Text(
                            'ยอมรับเงื่อนไขและข้อตกลงการใช้งาน',
                          ),
                          controlAffinity: ListTileControlAffinity.leading,
                        ),
                          ElevatedButton(
                            onPressed: () {
                              // อ้างอิงฟอร์มที่กำลังใช้งาน ตรวจสอบความถูกต้องข้อมูลในฟอร์ม
                              if (_formKey.currentState!.validate()) { //หากผ่าน
                                  formData['email'] = _text1.text;
                                  formData['password'] = _text2.text;
                                  formData['birthday'] = _text3.text;
                                  formData['gender'] = _selectedGenderText;
                                  formData['hobby'] = _checkedHobby;
                                  formData['maritalstatus'] = _seslectedMaritalStatus;
                                 // print(formData);
                                // แสดงข้อความจำลอง ใน snackbar
                                ScaffoldMessenger.of(context).showSnackBar(
                                  // นำค่าข้อมูลไปแสดงหรือใช้งานผ่าน controller
                                   SnackBar(content: Text('Process Data...${formData}')),
                                );
                              }
                            },
                            child: const Text('Submit'),
                          ),
                      ],
                  ),
                ),
              ),
            ),
        );
    }
}
  
// กำหนดข้อมูลสำหรับ radio
enum Gender { male, female }
 
    ผลลัพธ์ที่ได้
 


 
 
    เมื่อทำการ submit หรือ validate ฟอร์มผ่านแล้ว เราทำการเก็บค่าข้อมูลทั้งหมด ไว้ใน Map ที่ชื่อ
formData เพื่อนำไปใช้งานต่อ ข้างต้น เราแค่แสดงผลข้อมูลด้วย snackBar
 
    สำหรับเนื้อหาเกี่ยวกับการใช้งาน element ของฟอร์มเพิ่มเติมในตอนนี้ก็มีประมาณนี้ หวังว่าจะเป็แแนวทาง
นำไปปรับใช้งานต่อไป เนื้อหาตอนหน้า เราจะนำสิ่งที่ได้เรียนรู้เกี่ยวกับฟอร์มทั้งสองตอนนี้ ไปประยุกต์
กับการใช้งานฟอร์มที่บันทึกลงฐานข้อมูลหนังสือของบทความก่อนหน้า รอติดตาม


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


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

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


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



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



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









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









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











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