@@ -990,6 +990,37 @@ <h4>
990
990
</ pre >
991
991
</ section >
992
992
993
+ < section > < h3 > General information about writing data</ h3 >
994
+ < p >
995
+ Writing data is generally straightforward, but there are a few
996
+ gotcha's around how writing works with NFC.
997
+ </ p >
998
+ < p >
999
+ An NFC reader works by polling, so in order to be able to
1000
+ write to a tag, a tag first needs to be found and read, which
1001
+ means that polling needs to be initialized first.
1002
+ </ p >
1003
+ < p >
1004
+ If polling is not initiated already by first calling `scan()`,
1005
+ then the `write()` method will initiate it temporarily until a
1006
+ tag was found and read, and writing to it was attempted.
1007
+ </ p >
1008
+ < p >
1009
+ This means that the flow is that first a read it performed
1010
+ as the tag is first found, then followed by a write.
1011
+ </ p >
1012
+ < p >
1013
+ This means that if `scan()` is running and you have an event
1014
+ listener for the `reading` event, it will be dispatched once
1015
+ during a `write()` operation, which might not be the intended
1016
+ behavior.
1017
+ </ p >
1018
+ < p >
1019
+ In the following sections we will discuss how you can easily
1020
+ deal with this behavior, but first a few simple examples.
1021
+ </ p >
1022
+ </ section >
1023
+
993
1024
< section > < h3 > Write a text string</ h3 >
994
1025
< p >
995
1026
Writing a text string to an NFC tag is straightforward.
@@ -1008,20 +1039,101 @@ <h4>
1008
1039
1009
1040
< section > < h3 > Write a URL</ h3 >
1010
1041
< p >
1011
- In order to write an NDEF record of URL type, simply use NDEFMessage.
1042
+ In order to write an NDEF record of URL type, simply use NDEFMessage. Here
1043
+ we rely on async/await.
1012
1044
</ p >
1013
1045
< pre class ="example ">
1014
- const writer = new NDEFWriter ();
1015
- writer.write( {
1016
- records: [{ recordType: "url", data: "https://w3c.github.io/web-nfc/" }]
1017
- }).then(() = > {
1018
- console.log("Message written." );
1019
- }).catch(_ = > {
1046
+ const ndef = new NDEFReader ();
1047
+ try {
1048
+ ndef.write({
1049
+ records: [{ recordType: "url", data: "https://w3c.github.io/web-nfc/" }]
1050
+ } );
1051
+ } catch {
1020
1052
console.log("Write failed :-( try again.");
1021
- }) ;
1053
+ };
1022
1054
</ pre >
1023
1055
</ section >
1024
1056
1057
+ < section > < h3 > Handling initial reads while writing</ h3 >
1058
+ < p >
1059
+ In order to write, a tag needs to be found and thus read. This gives
1060
+ you the ability to check whether it is actually a tag that you want to
1061
+ write to or not, by checking existing data or serial number.
1062
+ </ p >
1063
+ < p >
1064
+ For this reason, it is recommended calling `write()` from a `reading`
1065
+ event.
1066
+ </ p >
1067
+ The below example shows how to coordinate between a common `reading`
1068
+ handler and one used specifically for a single write.
1069
+ </ p >
1070
+ < pre class ="example ">
1071
+ const reader = new NDEFReader();
1072
+ let ignoreRead = false;
1073
+
1074
+ reader.onreading(event => {
1075
+ if (ignoreRead) {
1076
+ return; // write pending, ignore read.
1077
+ }
1078
+
1079
+ console.log("We read a tag, but not during pending write!");
1080
+ }
1081
+
1082
+ function write(data) {
1083
+ ignoreRead = true;
1084
+ return new Promise((resolve, reject) => {
1085
+ reader.addEventListener("reading", event => {
1086
+ // Check if we want to write to this tag, or reject.
1087
+ reader.write(data).then(resolve, reject).finally(() => ignoreRead = false);
1088
+ }, { once: true });
1089
+ });
1090
+ }
1091
+
1092
+ await reader.scan();
1093
+ try {
1094
+ await write("Hello World");
1095
+ console.log("We wrote to a tag!")
1096
+ } catch(err) {
1097
+ console.error("Something went wrong", err);
1098
+ }
1099
+ </ pre >
1100
+ </ section >
1101
+
1102
+ < section > < h3 > Scheduling a write with a timeout</ h3 >
1103
+ < p >
1104
+ It can sometime be useful to set a time limit on a write operation.
1105
+ Like you ask the user to touch a tag, and if no tag is found within
1106
+ a certain amount of time, then you time out.
1107
+ </ p >
1108
+ < pre class ="example ">
1109
+ const reader = new NDEFReader();
1110
+ reader.onreading(event => console.log("We read a tag!"));
1111
+
1112
+ function write(data, { timeout } = {}) {
1113
+ return new Promise((resolve, reject) => {
1114
+ const ctlr = new AbortController();
1115
+ ctlr.signal.onabort = _ => reject("Time is up, bailing out!");
1116
+ if (typeof timeout == "number") {
1117
+ setTimeout(() => ctlr.abort(), timeout);
1118
+ }
1119
+
1120
+ reader.addEventListener("reading", event => {
1121
+ reader.write(data, { signal: ctlr.signal }).then(resolve, reject);
1122
+ }, { once: true });
1123
+ });
1124
+ }
1125
+
1126
+ await reader.scan();
1127
+ try {
1128
+ // Let's wait for 5 seconds only.
1129
+ write("Hello World", { timeout: 5_000 });}
1130
+ } catch(err) {
1131
+ console.error("Something went wrong", err);
1132
+ } finally {
1133
+ console.log("We wrote to a tag!");
1134
+ }
1135
+ </ pre >
1136
+ </ section >
1025
1137
1026
1138
< section > < h3 > Handle scanning errors</ h3 >
1027
1139
< p >
@@ -1044,6 +1156,37 @@ <h4>
1044
1156
</ pre >
1045
1157
</ section >
1046
1158
1159
+ < section > < h3 > Read a single tag, once</ h3 >
1160
+ < p >
1161
+ This example show you how to easily create a convenience function
1162
+ that just reads a single tag and then stops polling, saving
1163
+ battery life by cutting unneeded work.
1164
+ </ p >
1165
+ < p >
1166
+ The example could easily be extended to time out after a given
1167
+ amount of milliseconds.
1168
+ </ p >
1169
+ < pre class ="example ">
1170
+ const reader = new NDEFReader();
1171
+
1172
+ function read() {
1173
+ return new Promise((resolve, reject) => {
1174
+ const ctlr = new AbortController();
1175
+ ctlr.signal.onabort = reject;
1176
+ reader.addEventListener("reading", event => {
1177
+ ctlr.abort();
1178
+ resolve(event);
1179
+ }, { once: true });
1180
+ reader.scan({ signal: ctlr.signal }).catch(err => reject(err));
1181
+ });
1182
+ }
1183
+
1184
+ read().then(({ serialNumber }) => {
1185
+ console.log(serialNumber);
1186
+ })
1187
+ </ pre >
1188
+ </ section >
1189
+
1047
1190
< section > < h3 > Read data from tag, and write to empty ones</ h3 >
1048
1191
< p >
1049
1192
This example shows reading various different kinds of data which can be
@@ -1180,29 +1323,27 @@ <h4>
1180
1323
1181
1324
< section > < h3 > Write data and print out existing data</ h3 >
1182
1325
< p >
1183
- Writing data requires tapping an < a > NFC tag</ a > . If data should be
1184
- read during the same tap, we need to set the {{NDEFWriteOptions/ignoreRead}}
1185
- property to `false`.
1326
+ Writing data requires tapping an < a > NFC tag</ a > .
1186
1327
</ p >
1187
1328
< pre class ="example ">
1188
- const reader = new NDEFReader();
1189
- reader.scan().then(() => {
1329
+ const ndef = new NDEFReader();
1190
1330
1191
- reader.onreading = event => {
1192
- const decoder = new TextDecoder();
1193
- for (const record of event.message.records) {
1194
- console.log("Record type: " + record.recordType);
1195
- console.log("MIME type: " + record.mediaType);
1196
- console.log("=== data ===\n" + decoder.decode(record.data));
1197
- }
1198
- };
1331
+ ndef.onreading = async event => {
1332
+ const decoder = new TextDecoder();
1333
+ for (const record of event.message.records) {
1334
+ console.log("Record type: " + record.recordType);
1335
+ console.log("MIME type: " + record.mediaType);
1336
+ console.log("=== data ===\n" + decoder.decode(record.data));
1337
+ }
1199
1338
1200
- const writer = new NDEFWriter();
1201
- return writer.write("Writing data is fun!", { ignoreRead: false });
1339
+ try {
1340
+ await ndef.write("Overriding data is fun!");
1341
+ } catch(error) {
1342
+ console.log(`Write failed :-( try again: ${error}.`);
1343
+ }
1344
+ };
1202
1345
1203
- }).catch(error => {
1204
- console.log(`Write failed :-( try again: ${error}.`);
1205
- });
1346
+ ndef.scan();
1206
1347
</ pre >
1207
1348
</ section >
1208
1349
@@ -1224,7 +1365,7 @@ <h4>
1224
1365
};
1225
1366
1226
1367
// Stop listening to NDEF messages after 3s.
1227
- setTimeout(() => controller.abort(), 3000 );
1368
+ setTimeout(() => controller.abort(), 3_000 );
1228
1369
</ pre >
1229
1370
</ section >
1230
1371
@@ -2203,21 +2344,15 @@ <h2>The <dfn>record type</dfn> string</h2>
2203
2344
< h3 > The < dfn > NDEFWriteOptions</ dfn > dictionary</ h3 >
2204
2345
< pre class ="idl ">
2205
2346
dictionary NDEFWriteOptions {
2206
- boolean ignoreRead = true;
2207
2347
boolean overwrite = true;
2208
2348
AbortSignal? signal;
2209
2349
};
2210
2350
</ pre >
2211
- < p >
2212
- When the value of the < dfn > ignoreRead</ dfn > property is `true`, the
2213
- < a > NFC reading algorithm</ a > will skip reading < a > NFC tag</ a > s for the
2214
- < a > activated reader objects</ a > .
2215
- </ p >
2216
2351
< p >
2217
2352
When the value of the < dfn > overwrite</ dfn > property is
2218
2353
`false`, the < a href ="#steps-write "> write algorithm</ a >
2219
- will read the < a > NFC tag</ a > regardless of the `ignoreRead` value
2220
- to determine if it has < a > NDEF</ a > records on it, and if yes, it will not
2354
+ will read the < a > NFC tag</ a > to determine if it has
2355
+ < a > NDEF</ a > records on it, and if yes, it will not
2221
2356
execute any pending write.
2222
2357
</ p >
2223
2358
< p >
@@ -3512,9 +3647,6 @@ <h3><dfn>Writing content</dfn></h3>
3512
3647
< li >
3513
3648
If < a > NFC is suspended</ a > , abort these steps.
3514
3649
</ li >
3515
- < li >
3516
- If there is a < a > pending write tuple</ a > and its writer's option's ignoreRead is `true`, abort these steps.
3517
- </ li >
3518
3650
< li >
3519
3651
If the < a > NFC tag</ a > in proximity range does not expose < a > NDEF</ a >
3520
3652
technology for reading or formatting, run the following sub-steps:
0 commit comments