NEWS
[HowTo] Skripte im VIS Editor mit jQuery
-
erstmal vielen dank an @scrounger, der mir sein script zur verfügung gestellt hat.
es gibt viele youtube videos, um jQuery zu lernen - ich selbst suche in google mit jQuery als anfangssuchwort - da wird man immer fündig
um das ganze auszuprobieren und zu testen, braucht man um die entwicklertools in google chrome. irgendwo auf der seite (oder auf einem widget) mit der rechten maustaste auf "untersuchen" klicken. dann öffnet sich ein fenster. dort hat man unter anderem 2 tabs - console und elemente. in der console sieht man die logs beim laden - und auch die fehler. unter elemente kann man den aufbau der webseite bzw. VIS sehen und sich aussuchen, was man beabeiten willmit jQuery kann man z.b. sehr gut widgets in der VIS manipulieren oder function's starten.
die folgende function scrollt die webseite auf den anfang der seite
function myupFunction() { $('html,body').scrollTop(0); }
die frage bleibt nun, wann das passieren soll: auch dazu nutzen ich jQuery
$('.seiteNachObenScrollen').click(function () { console.log( "ich werde scrollen!" ); myupFunction() });
jedes element, dem ich die class seiteNachObenScrollen zuweise und ich in der runtime anklicke, wird nun dazu führen, dass die seite nach oben scrollt - doch leider funktioniert das nicht
WARTEN AUF .... : nun zum eigentlichen problem - die jQuery definitionen werden ausgeführt, bevor die elemente ( z.b. widgets) vollständig geladen sind - das bedeutet: die ganze sache läuft ins leere, den jQuery hat die zu manipulierenden elemente nicht gefunden
ein weiteres beispiel: wird die größe des browser fensters kleiner, soll sich ein bild (src des bildes) ändern. das widget bekommt von der vis eine id ( w00008) - im widget selbst ist die bild-src definiert worden. in diesem fall muss das widget über die id angesprochen werden, um es zu ändern.
die trigger function wäre:
$(window).resize(function () { ........});
die ausführende jQuery function, sieht so aus (nur die src des img-widgets mit der id w00008 wird angesprochen):
$( "#w00008" ).contents().find( "img" ).attr({ "src": "https://forum.iobroker.net/assets/uploads/profile/4114-profileavatar-1609575687456.png"});
und genau hier ist unser problem - es muss sicher gestellt sein, dass die VIS das widget schon geladen hat. @scrounger hat dazu folgende WARTE-scripte erstellt. diese werden in den script-tab im vis-editor eingefügt. diese functions werden aufgerufen und die jQuery -abfragen und- function werden dann darin ausgeführt - so wird sichergestellt, dass die widgets oder andere elemente auch geladen wurden
wait for element function waitForElement(parent, elementPath, wid, widgetName, callBack, counter = 0, debug = false) { if (counter < 100) { setTimeout(function () { if (parent.find(elementPath).length > 0) { if (debug) console.log(`[${widgetName} ${wid}] it took ${counter}ms to wait for the element '${elementPath}'`); callBack(); } else { if (debug) console.log(`[${widgetName} ${wid}] wait for element '${elementPath}'`); counter++ waitForElement(parent, elementPath, wid, widgetName, callBack, counter, debug); } }, 1); } else { if (debug) console.warn(`[${widgetName} ${wid}] stop waiting after ${counter} retries`); callBack(); } }
aufruf beispiel: warten auf class
waitForElement($('body'),'.seiteResizen', 'dummy', 'dummy', function () { // Elemente mit der Class vollständig geladen, wir können irgendwas damit machen }, 0, true);
aufruf beispiel: warten auf widget
waitForElement($('body'),'#w00015', 'dummy', 'dummy', function () { // Widget ist vollständig geladen, wir können irgendwas damit machen }, 0, true);
wait for all widgets es wird sichergestellt, dass alle widgets geladen sind - hier alle jQuery's unterbringen, die auf ein widget warten müssen function waitForWidgets(callBack, counter = 0, debug = true) { if (counter < 500) { setTimeout(function () { if (vis.widgets && vis.widgets !== null && Object.keys(vis.widgets).length > 0) { callBack(); } else { if (debug) console.log(`[waitForWidgets] wait for widgets`); counter++ vis.binds.materialdesign.helper.waitForWidgets(callBack, counter, debug); } }, 1) } else { console.warn(`[waitForWidgets] stop waiting for vis widgets after ${counter} retries`); callBack(); } }
aufruf beispiel:
waitForWidgets(function () { // Widgets sind vollständig geladen, wir können irgendwas damit machen }, 0, true);
-
Und noch ein paar weitere Funktionen:
State abrufen (Wert eines Datenpunktes):
function getState(id, callback) { vis.conn._socket.emit('getState', id, function (err, obj) { if (!err && obj) { callback(obj) } else { callback(undefined) } }); }
Async State abrufen (Wert eines Datenpunktes):
async function getStateAsync(id) { return new Promise((resolve, reject) => { vis.conn._socket.emit('getState', id, function (err, res) { if (!err && res) { resolve(res); } else { resolve(undefined); } }); }); }
State schreiben (Wert in Datenpunkt schreiben):
function setState(id, value) { this.vis.setValue(id, value); }
Objekt abrufen:
function getObject(id, callback) { vis.conn._socket.emit('getObject', id, function (err, obj) { if (!err && obj) { callback(obj) } else { callback(undefined) } }); }
Async Objekt abrufen:
async function getObjectAsync(id) { return new Promise((resolve, reject) => { vis.conn._socket.emit('getObject', id, function (err, res) { if (!err && res) { resolve(res); } else { resolve(undefined); } }); }); }
Fehlermeldungen der VIS Runtime in einen Datenpunkt schreiben (obere Funktionen werden dafür benötigt):
window.onerror = async function (msg, url, lineNo, columnNo, error) { let idError = `0_userdata.0.visError`; let idErrorCount = `0_userdata.0.visErrorCount`; let errorList = []; let errorState = await getStateAsync(idError); if(errorState && errorState.val){ errorList = JSON.parse(errorState.val); } errorList.push({ time: moment().format("DD.MM.YYYY - HH:mm:ss"), msg: JSON.stringify(msg), view: vis.activeView, instance: vis.instance, error: error, url: url, lineNo: lineNo, columnNo: columnNo }); setState(idErrorCount, errorList.length); setState(idError, JSON.stringify(errorList)); return false; }
-
Ich bin gerade auf dieses HowTo gestoßen und stelle fest, dass es meinen Bedarf fast erfüllt, also danke erstmal dafür
Die Funktion
waitForElement
habe ich ausprobiert, um bei einem Date-Picker dasreadonly
-Attribut zu setzen, damit bei der Bedienung auf dem Tablet nicht die Tastatur aufspringt. Das Funktioniert soweit, jedoch ist das Problem, dass der Date-Picker sich nicht auf der Start-View befindet sondern auf irgend einer Unter-View und es nicht vorhersehbar ist, wann mal jemand diese View öffnet.Wie könnte denn dafür eine Lösung aussehen?
-
@scrounger sagte in [HowTo] Skripte im VIS Editor mit jQuery:
State abrufen (Wert eines Datenpunktes):
function getState(id, callback) { vis.conn._socket.emit('getState', id, function (err, obj) { if (!err && obj) { callback(obj) } else { callback(undefined) } }); }
Wenn ich das richtig verstanden habe, ist das die Definition der Funktion. Die Nutzung / der Aufruf erfolgt dann via
var Test_Variable; Test_Variable = getState('0_userdata.0.Test_Datenpunkt', xxx);
? Da ich (noch) nicht genug Wissen über callback-Funktionen habe, bin ich derzeit am Grübeln, was ich in diesem speziellen Fall für den Parameter "callback" einsetzen muß, und wo es vielleicht etwas gibt, um das nachzulesen/sich anzueignen.
Bei allen Versuchen, die ich bisher für "xxx" unternommen habe, sah es so aus, als ob in Test_Variable nichts geschrieben wird, weil in Test_Datenpunkt immer (null) geschrieben wurde. Fehlermeldung im Konsolen-Log:
Uncaught TypeError: callback is not a functionHättest Du einen Hinweis für mich?