-
Bug
-
Resolution: Duplicate
-
Major
-
8.6.2
-
None
-
Security Level: Jimmy
-
None
-
None
Steps to Reproduce
http://zkfiddle.org/sample/1hv4ehq/1-quagga-listener-not-clean-on-unbind
run locally
click remove button
Current Result
barcodescanner is removed, quagga reader is not
see console repeating callback error very rapidely:
zkmax.barscanner.wpd:36 Uncaught TypeError: Cannot read property 'getContext' of undefined at Object.callback (zkmax.barscanner.wpd:36) at n (zkmax.barscanner.wpd:4) at zkmax.barscanner.wpd:4 at Array.forEach (<anonymous>) at Object.publish (zkmax.barscanner.wpd:4) at v (zkmax.barscanner.wpd:4) at Worker.n.worker.onmessage (zkmax.barscanner.wpd:4) (anonymous) @ zkmax.barscanner.wpd:36 n @ zkmax.barscanner.wpd:4 (anonymous) @ zkmax.barscanner.wpd:4 publish @ zkmax.barscanner.wpd:4 v @ zkmax.barscanner.wpd:4 n.worker.onmessage @ zkmax.barscanner.wpd:4
Expected Result
removing a barcodescanner should also unsubscribe its listeners from the quagga library
Debug Info
quagga has an onDetected / offDetected and onProcessed / offProcessed methods to add or remove callbacks from the quagga reader library
Root Cause
missing unbind behavior / missing self cleaning listener
Workaround
<script><![CDATA[ zk.afterLoad('zkmax.barscanner', function() { var xBarcodescannerStatic = {}; zk.override(zkmax.barscanner.Barcodescanner, xBarcodescannerStatic ,{ _quaggaInit: function (wgt, video, canvas, target) { //zkmax.barscanner.Barcodescanner.quaggaApp.init(wgt); var readerType = [], reader = wgt._QUAGGAReader; wgt.debug = false; reader._ready = false; readerType = zkmax.barscanner.Barcodescanner._quaggaTypeFilter(wgt); //Before quagga.init, the video status should be 4, so it has videoWidth and videoHeight attribute to set the //size of canvas new Promise(function (resolve, reject) { var waitVideo = setInterval(function () { if (video.readyState == 4) { clearInterval(waitVideo); resolve(); } }, 50, wgt); }).then(function () { reader.init({ locate: true, inputStream: { name: 'Live', type: 'LiveStream', target: target, // Or '#yourElement' (optional) area: { // defines rectangle of the detection/localization area top: '0%', // top offset right: '0%', // right offset left: '0%', // left offset bottom: '0%' // bottom offset }, size: zkmax.barscanner.Barcodescanner._quaggaCanvasDim(wgt).width }, frequency: 1000, decoder: { readers: readerType, // List of active readers debug: { drawBoundingBox: false, showFrequency: false, drawScanline: false, showPattern: false }, multiple: false }, locator: { halfSample: false, patchSize: 'medium', // x-small, small, medium, large, x-large debug: { showCanvas: wgt.debug, showPatches: wgt.debug, showFoundPatches: wgt.debug, showSkeleton: wgt.debug, showLabels: wgt.debug, showPatchLabels: wgt.debug, showRemainingPatchLabels: wgt.debug, boxFromPatches: { showTransformed: wgt.debug, showTransformedBox: wgt.debug, showBB: wgt.debug } } }, debug: wgt.debug }, function (err) { if (err) { zk.error(err); return; } reader.canvas = jq.extend(true, {}, zkmax.barscanner.quagga.canvas); reader._ready = true; reader._reset = true; reader._consistencyBuffer = []; }); }); var onProcessedCallback = function (result) { if(wgt.$n() == null){ reader.offProcessed(onProcessedCallback); return; } var q = zkmax.barscanner.quagga, drawingCanvas = wgt.$n('canvas'), drawingCtx = drawingCanvas.getContext('2d'); if (result) { if (result.boxes) { drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute('width')), parseInt(drawingCanvas.getAttribute('height'))); result.boxes .filter(function (box) { return box !== result.box; }) .forEach(function (box) { q.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: 'green', lineWidth: 2}); }); } if (result.box) q.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: 'blue', lineWidth: 2}); if (result.codeResult && result.codeResult.code) q.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3}); } } reader.onProcessed(onProcessedCallback); reader.onDetected(function (result) { if (result[0] != undefined) { result = result[0]; } var errors = result.codeResult.decodedCodes .filter(function (i) { return i.error !== undefined; }) .map(function (i) { return i.error; }), errorSum = errors.reduce(function (prev, next) { return prev + next; }), errorFactor = errorSum / errors.length; if (errorFactor <= wgt._errorAcceptance) { var format = result.codeResult.format.replace('_', ''), value = result.codeResult.code, buf = reader._consistencyBuffer; buf.push(value); if (buf.length > wgt._consistencyBufferSize) buf.shift(); if (buf.filter(function (v) { return v === value; }).length >= wgt._consistencyThreshold) { reader._consistencyBuffer = []; wgt._doDetect(format, value); reader.processing = false; reader.pause(); } } }); } }); zkmax.barscanner.Barcodescanner._initLibrary(); }); ]]></script>