Video Tutorial

Labels
AJAX(112) Apple(1) Application Builder(242) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(11) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) DotNetNuke(12) EASE(20) Email(6) Features(99) Firebird(1) Form Builder(14) Globalization and Localization(6) Hypermedia(2) Installation(4) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(15) OAuth(5) OAuth Scopes(1) OAuth2(6) Offline(14) Oracle(10) PKCE(1) PostgreSQL(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(163) Reports(48) REST(26) RESTful(21) RESTful Workshop(13) RFID tags(1) SaaS(7) Security(75) SharePoint(12) SPA(5) SQL Anywhere(3) SQL Server(26) Stored Procedure(4) Teamwork(15) Tips and Tricks(81) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(331) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(39) Web.Config(9) Workflow(28)
Archive
Blog
Video Tutorial
Friday, May 15, 2020PrintSubscribe
Tutorial: Barcodes, QR codes, and RFID tags
Learn to create the Order Entry Form that works offline and online. The form will handle barcodes, QR codes, and RFID tags. The tutorial explains how to calculate the default values, extended price, and order total.


We start with the live demo of the app that will be created in this tutorial. Next we proceed to create the Order Entry Form shown in the demo and make it work in online and offline modes. The next iteration of the app is using UI Automation to implement the barcode processing for Product inventory, QR-code processing for Customer Loyalty Cards, RFID tags to handle Employee Access Cards. We bind it all together for Hands-Free Order Entry. The final part of the tutorial concentrates on creating the Kiosk-style presentation for the Order Entry Form.

Part 1 - Demo (30 minutes)

03:20 - Introduction
07:18 - Barcodes and Product Inventory
09:28 - QR codes and Customer Loyalty Cards
11:05 - RFID Access Cards and Employees
13:02 - Entering order line items with the barcode scanner
15:40 - Linking loyalty cards with the QR code scanner
16:51 - Linking employee to the order with the RFID reader
20:36 - Entering the lines items in “inventory” mode
24:38 - Kiosk presentation of Order Entry Form

Part 2 - Building Order Entry Form (1 hour 42 minutes)

0:32:49 - Introduction
0:33:16 - Database Diagram of Order Entry Form
0:35:58 - Configuring Sample Database
0:40:20 - Creating data models for Orders, Customers, Employees, and Shippers
0:48:52 - Creating data models for Order Details, Products, Categories, and Suppliers
0:54:36 - Modifying Menu
0:55:35 - Linking Order and Order Details
1:06:20 - Calculating default values with SQL business rules
1:09:08 - Calculating default values with JavaScript business rules
1:15:25 - Copying the Unit Price
1:18:24 - Calculating Extended Price with JavaScript
1:32:23 - Copying the shipping information from the Customer to the Order
1:37:14 - Calculating the Order Total
2:00:32 - Taking Orders in offline mode
2:12:25 - Syncing offline orders with the “online” database

Part 3 - Barcode Input and UI Automation (3 hours)

2:15:03 - Enabling the barcode input
2:26:45 - Simulating scanning of a barcode
2:33:20 - Low-level barcode processing
2:40:56 - Introducing UI Automation
2:42:33 - Integrating barcodes in the Product Inventory
3:20:09 - Integrating barcodes and QR-codes to handle Customer  Loyalty Cards
3:35:46 - Integrating RFID Access Cards to identify the Employees
3:46:55 - Using Data Queries during UI Automation
3:54:45 - Implementing Hands-Free Order Entry
5:08:22 - Taking orders in offline mode with barcodes, QR codes, and RFID tags

Part 4 - Kiosk UI (2 hours)

5:14:33 - Creating a Kiosk-style Order Entry presentation
6:11:55 - Adding Numeric Pad for parameter input
6:34:20 - Displaying date selector and pick list
6:43:35 - Making Order Entry Kiosk responsive
7:14:26 - Taking orders in the offline Kiosk

The source code produced in the tutorial is available at https://codeontime.com/blog/2020/05/hello-barcodes-sample-code.

The following equipment was used in the tutorial:

Inateck Bluetooth Barcode Scanner
https://www.amazon.com/gp/product/B074M6RTM3


Koolertron Wireless 2D Barcode Scanner
https://www.amazon.com/gp/product/B0716PQYJP


RFID Reader 125KHz
https://www.amazon.com/gp/product/B07TMNZPXK

Tuesday, May 12, 2020PrintSubscribe
"Hello Barcodes!" Sample Code
The tutorial "Barcodes, QR codes, and RFID tags" results in the production of the following code:

~/touch-settings.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "barcode": {
    "enabled": true
  },
  "ui": {
    "automation": {
      "enabled": true,
      "kiosk": {
        "enabled": true,
        "gapColor": true,
        "maxWidth": 2000,
        "copyright": false,
        "fullscreen":  false
      }
    }
  }
}

~/js/MyApp.js

  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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
/*eslint eqeqeq: ["error", "smart"]*/

(function () {

    var Barcodes = {
        LoyaltyCard: /^lc/i,
        AccessCard: /^000/
    };

    // business rules

    $app.rules.Orders = {
        Calculate: function (dataView, args) {
            var freight = dataView.data().Freight;
            if (freight == null)
                freight = 0;

            $app.execute({ from: 'OrderDetails' }).then(function (result) {
                var total = 0;
                result.OrderDetails.forEach(function (detail) {
                    total += detail.ExtendedPrice;
                });
                if (total > 0)
                    total += freight;
                $app.input.execute({ OrderTotal: total });
            });
            return false;
        },
        after: {
            New: function (dataView, args) {
                var order = dataView.data();
                $app.input.execute({ OrderDate: new Date(), OrderNumber: order.OrderID });
            }
        }
    };

    $app.rules.OrderDetails = {
        after: {
            New: function (dataView, args) {
                $app.input.execute({ Discount: 0, Quantity: 1 });
            }
        },
        Calculate: function (dataView, args) {
            var details = dataView.data();

            var unitPrice = details.UnitPrice;
            if (unitPrice == null)
                unitPrice = 0;

            var quantity = details.Quantity;
            if (quantity == null)
                quantity = 0;

            var discount = details.Discount;
            if (discount == null)
                discount = 0;

            var extendedPrice = unitPrice * quantity * (1 - discount);
            $app.input.execute({ ExtendedPrice: extendedPrice })

            return false;
        }
    }

    // Barcode Input Simulator

    $(document).on('context.app', function (e) {
        e.context.push({
            hidden: true,
            text: 'Scan Product 1',
            shortcut: 'Ctrl+Shift+1',
            callback: () => $app.input.barcode('842776107183')
        });
        e.context.push({
            hidden: true,
            text: 'Toggle Kiosk',
            shortcut: 'Ctrl+Shift+K',
            callback: () => $app.touch.kiosk(!$app.touch.kiosk())
        });
    });

    // low-level barcode processing

    //$(document).on('barcode.app', function (e) {
    //    $app.touch.notify('I am handling this: ' + e.text);
    //    setTimeout(function () {
    //        $app.input.barcode(true);
    //    }, 7000)
    //    return false;
    //});

    //
    // Special Workflow Control Barcodes
    //

    $app.ifThisThenThat((app, context) =>
        app.if(context.barcode('ORDER_LINE_SETQTY').input('numpad.number', v => v > 0))
            .then(() => app.action('edit', 'details'))
            .then(() => app.val({
                'qua': context.input('numpad.number')
            }))
            .then(() => app.action('save'))
            .then(() => app.notify(false))
            .then(() => app.input('numpad', null))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.barcode('ORDER_LINE_SETQTY'))
            .then(() => app.notify('Please use the numeric pad to enter the quantity.'))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.barcode('ORDER_LINE_INC'))
            .then(() => app.action('edit', 'details'))
            .then(() => app.inc('qua'))
            .then(() => app.action('save'))
            .then(() => app.notify(false))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.barcode('ORDER_LINE_DEC'))
            .then(() => app.action('edit', 'details'))
            .then(() => app.dec('qua'))
            .then(() => app.action('save'))
            .then(() => app.notify(false))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.barcode('ORDER_LINE_5OFF'))
            .then(() => app.action('edit', 'details'))
            .then(() => app.val('disc', .05))
            .then(() => app.action('save'))
            .then(() => app.notify(false))
    );

    //
    // Hands-Free Order Entry
    //

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').list().barcode(Barcodes.LoyaltyCard).field('ord+num').action('new order'))
            .then(() => app.action('new order'))
            .then(() => app.val({
                'freight': 10.00,
                'via company': 'Federal Shipping',
                'loyalty': context.barcode()
            }))
            .then(() => app.notify('Please scan the order items.'))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').editing().barcode(Barcodes.LoyaltyCard).field('loyalty').val('loyalty', null))
            .then(() => app.val({
                'loyalty': context.barcode()
            }))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').editing().barcode(Barcodes.LoyaltyCard).field('loyalty'))
            .then(() => app.confirm('Assign a different loyalty card?'))
            .then(() => app.val({
                'loyalty': context.barcode()
            }))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').list().barcode(Barcodes.AccessCard).field('ord+num').action('new order'))
            .then(() => app.action('new order'))
            .then(() => app.val({
                'freight': 10.00,
                'via company': 'Federal Shipping',
                'access': context.barcode()
            }))
            .then(() => app.notify('Please scan the order items.'))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').editing().barcode(Barcodes.AccessCard).field('access'))
            .then(() => app.val({
                'access': context.barcode()
            }))
    );

    //
    // Product Barcode is scanned in Order Form
    //

    function tomorrow() {
        var d = new Date();
        d.setDate(d.getDate() + 1);
        return d;
    }

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').list().barcode().field('ord+num').action('new order'))
            .then(() => app.action('new order'))
            .then(() => app.val({
                'freight': 10.00,
                'via company': 'Federal Shipping',
                'required': tomorrow()
            }))
            .then(() => app.action('new order details', 'order details'))
            .then(() =>
                app.val({
                    'barcode': context.barcode(),
                    'qua': 0
                })
                    .fail(() =>
                        app.discard('Product not found.'))
            )
            .then(() => app.inc('qua', context.barcode()))
            .then(() => app.action('save'))
            .then(() => app.notify(false))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').editing().barcode().field('ord+num').row('barcode', context.barcode(), 'details'))
            .then(() => app.row('barcode', context.barcode(), 'details'))
            .then(() => app.action('edit', 'details'))
            .then(() => app.inc('qua', context.barcode()))
            .then(() => app.action('save'))
            .then(() => app.notify(false))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('orders').editing().barcode().field('ord+num'))
            .then(() => app.action('new', 'details'))
            .then(() =>
                app.val({
                    'barcode': context.barcode(),
                    'qua': 0
                })
                    .fail(() =>
                        app.discard('Product not found.'))
            )
            .then(() => app.inc('qua', context.barcode()))
            .then(() => app.action('save'))
            .then(() => app.notify(false))
    );

    //
    // Using $app.execute to read data
    //

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.not().page('employee').barcode(Barcodes.AccessCard))
                .then(() =>
                    $app.execute({
                        controller: 'Employees',
                        filter: { AccessCard: context.barcode().unwrap() },
                        as: 'emp'
                    })
                        .then((result) =>
                            result.emp.length > 0 ?
                                app.notify(result.emp[0].FirstName + ' ' + result.emp[0].LastName +
                                    ', please scan the access card in the order form.') :
                                app.notify('Unknown access card: ' + context.barcode())
                        )
                )
    );

    //
    // Product Inventory
    //

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('products').list().barcode().field('barcode').row('barcode', context.barcode()))
            .then(() => app.row('barcode', context.barcode()))
    );

    $app.ifThisThenThat((app, context) =>
        app.if(context.page('products').list().barcode().field('barcode'))
            .then(() => app.notify('Please select a product to assign a barcode.'))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('products').editing().barcode().field('barcode'))
                .then(() => app.val('barcode', context.barcode()))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('products').reading().field('barcode').barcode())
                .then(() =>
                    app.confirm('Assign the barcode ' + context.barcode() + ' to the product "' +
                        context.val('product') + '"?'))
                .then(() =>
                    app.action('edit'))
                .then(() =>
                    app.val('barcode', context.barcode()))
                .then(() =>
                    app.action('save'))
    );

    //
    // Customer Loyalty Cards
    //

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('customer').list().barcode(Barcodes.LoyaltyCard).field('loyalty').row('loyalty', context.barcode()))
                .then(() => app.rowFilter('loyalty', context.barcode()))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('customer').list().barcode(Barcodes.LoyaltyCard).field('loyalty'))
                .then(() => app.filter('loyalty', context.barcode()))
                .then(() => app.notify('Loyalty card not found: ' + context.barcode()))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('customer').editing().barcode(Barcodes.LoyaltyCard).field('loyalty'))
                .then(() => app.val('loyalty', context.barcode()))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('customer').reading().field('loyalty').barcode(Barcodes.LoyaltyCard))
                .then(() => app.confirm('Assign the loyalty card ' + context.barcode() + ' to the customer "' +
                    context.val('company') + '"?'))
                .then(() => app.action('edit'))
                .then(() => app.val('loyalty', context.barcode()))
                .then(() => app.action('save'))
    );

    //
    // Employee Access Cards
    //

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('employee').list().barcode(Barcodes.AccessCard).field('access').row('access', context.barcode()))
                .then(() => app.rowFilter('access', context.barcode()))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('employee').list().barcode(Barcodes.AccessCard).field('access'))
                .then(() => app.filter('access', context.barcode()))
                .then(() => app.notify('Access card not found: ' + context.barcode()))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('employee').editing().barcode(Barcodes.AccessCard).field('access'))
                .then(() => app.val('access', context.barcode()))
    );

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('employee').reading().field('access').barcode(Barcodes.AccessCard))
                .then(() => app.confirm('Assign the access card ' + context.barcode() + ' to the employee "' +
                    context.val('Last') + '"?'))
                .then(() => app.action('edit'))
                .then(() => app.val('access', context.barcode()))
                .then(() => app.action('save'))
    );

    var ordersDisplay2 = [
        { flow: 'row' },
        { flow: 'row' },
        {
            flow: 'column',
            label: 'Lines',
            in: 'details',
            count: 50,
            height: 'fill',
            alter: {
                _md: {
                    tab: 'Lines'
                }
            },
            '>': {},
            '#': {},
            'Product Name': {},
            'price': {
                alter: {
                    _lg: {
                        hidden: true
                    }
                }
            },
            'qua': { label: 'Qty' },
            'Disc': {
                label: 'Disc',
                alter: {
                    _lg: {
                        hidden: true
                    }
                }
            },
            'ext+price': { label: 'Ext. Price' },
            'barcode': { flow: 'row', label: false, width: '30%', wrap: false },
            'price2': {
                clone: 'price',
                flow: 'column',
                label: false,
                hidden: true,
                alter: {
                    _lg: {
                        hidden: null
                    }
                }
            },
            'supplier': {
                flow: 'column', label: false, wrap: true,
                alter: {
                    _lg: {
                        hidden: true
                    }
                }
            },
            'category': { flow: 'column', label: false, align: 'right' }
        },
        {
            alter: {
                _md: {
                    hidden: true
                }
            }
        },
        {
            alter: {
                _md: {
                    tab: 'Ship',
                    height: 'fill'
                }
            },
            'order date': { label: 'Ordered' },
            'required': { label: 'Required' },
            'ship via': {},
            'ship+phone': { label: 'Phone' },
            'salesPerson': {
                flow: 'column',
                expression: order => order.val('first') + ' ' + order.val('last'),
                when: order => order.val('last') != null,
                label: 'Employee',
                accentValue: true,
                alter: {
                    _md: {
                        flow: null
                    }
                }
            },
            'freight': {},
            'total': {
                flow: 'row',
                largeValue: true,
                colorValue: 'green',
                alter: {
                    _md: {
                        hidden: true
                    }
                }
            }
        },
        {
            flow: 'column',
            alter: {
                _md: {
                    hidden: true
                }
            }
        },
        {
            flow: 'column',
            label: 'Customer',
            width: '4x',
            height: 'fill',
            alter: {
                _md: {
                    flow: null,
                    tab: 'Customer',
                    height: 'fill'
                }
            },
            'ship name': {},
            'company': { label: false, medium: true, accent: true },
            'cust+ph': { label: 'Phone' },
            'loyalty': { label: 'Loyalty Card' },
            'ship addr': { label: false, dense: true },
            'city, region, zip': {
                expression: order =>
                    order.val('city') ?
                        order.val('city') + ', ' + (order.val('region') || '') + ' ' + order.val('postal') :
                        null,
                label: false,
                dense: true
            },
            'country': { label: false, dense: true }
        },
        {
            'total': {
                flow: 'row',
                largeValue: true,
                colorValue: 'green',
                hidden: true,
                alter: {
                    _md: {
                        hidden: null
                    }
                }
            }
        },
        {
            alter: {
                _md: {
                    hidden: true
                }
            }
        },
        {
            'numpad': {
                label: 'Search products or enter quantity',
                alter: {
                    _md: {
                        hidden: true,
                        compact: true
                    }
                }
            }
        },
        { flow: 'column' },
        {
            flow: 'column',
            width: '4x',
            height: 'fill',
            alter: {
                _sm: {
                    width: '2x'
                }
            },
            'save': {
                alter: {
                    _sm: {
                        text: false
                    }
                }
            },
            'cancel': {
                alter: {
                    _sm: {
                        text: false
                    }
                }
            }
        },
        {
            in: 'details',
            append: true,
            'Set quantity': {
                dark: true,
                barcode: 'ORDER_LINE_SETQTY',
                when: line => line.val('prod')
            },
            'delete': {
                darkest: true,
                text: false,
                wide: true
            }
        },
        {
            in: 'details',
            append: true,
            'Archive': {
                text: false,
                icon: 'material-icon-archive',
                when: line => line.val('prod'),
                barcode: 'ORDER_LINE_ARCHIVE'
            },
            'Increase Quantity': {
                text: false,
                dark: true,
                icon: 'material-icon-add',
                when: line => line.val('prod'),
                barcode: 'ORDER_LINE_INC'
            },
            'Decrease Quantity': {
                text: false,
                dark: true,
                icon: 'material-icon-remove',
                when: line => line.val('prod'),
                barcode: 'ORDER_LINE_DEC'
            },
            'Numeric Pad': {
                icon: 'material-icon-dialpad',
                text: false,
                darkest: true,
                perform: {
                    show: 'numpad',
                    hide: 'numpad'
                },
                hidden: true,
                alter: {
                    _md: {
                        hidden: null
                    }
                }
            }
        },
        {
            append: true,
            'Pay with credit card': {
                darkest: true,
                perform: {
                    pick: 'ord+date'
                }
            },
            'No sale': {
                dark: true,
                perform: {
                    pick: 'cust+comp'
                }
            }
        },
        {
            in: 'details',
            append: true,
            '5% discount': {
                wide: true,
                barcode: 'ORDER_LINE_5OFF',
                when: detail => detail.val('prod'),
                alter: {
                    _md: {
                        wide: false
                    }
                }
            }
        },
        { flow: 'column' },
        { flow: 'row' }
    ];

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('Orders').field('order number').editing().not().display(ordersDisplay2))
                .then(() => app.display(ordersDisplay2))
    );

    var ordersDisplay1 = 'Please scan a loyalty card or a product barcode to start your order.';

    $app.ifThisThenThat(
        (app, context) =>
            app.if(context.page('Orders').list().field('order number').not().display(ordersDisplay1))
                .then(() => app.display(ordersDisplay1))
    );




})();
Wednesday, April 25, 2018PrintSubscribe
Inline Editing in Multi-Level Master-Detail Pages

Hey there! We are working on completing the video tutorial covering the new multi-level master-detail support in the release 8.7.0.0.  The release has been accumulating numerous features over the past three months. The wait is almost over.

The screenshot shows a master detail page with three connected data views (Customers, Orders, Order Details).

User is entering the freight amount for an order in the screenshot. Inline Editing makes it possible. The feature requires zero programming. All of your grid views support editing as shown at https://www.youtube.com/watch?v=L4tbC5ZeUwA&index=1&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb.

Notice the horizontal scrollbars showing the depth of grids. The styling of pager has been changed as well.
Three-Level master detail page in app created with Code On Time.

All types of input are working in inline editing mode, just like they do in the forms. Here is  a lookup control with auto-complete feature. Enormous amount of work has been put in comprehensive keyboard navigation support in forms.

Touch UI supports data input in Inline Editing mode.

Apps created with Code On Time support inline editing on mobile devices. The screenshot shows “mobile” inline editing mode.

Mobile inline editing is unique and exclusive to apps created with Code On Time.

Inline Editing is fully supported in List and Cards modes as well.

Edit data inline in grids, lists, and cards or your app.

Don’t forget – native apps, custom search, and a host of other features are coming your away. Subscribe to our YouTube channel and get notified when the new tutorials are out!

Continue to Video Tutorials