Ok here is something , that I think should be fairly simple , that I cant get my head around.
I am building a MQTT device tracker with a web front end. Fairly strait forward , I keep track of regular incoming payload via MQTT and get notified it the incoming payload timeout.
I am using SQLite to track the topic's and then run a query to track the time received. All and it works quite well but as per ususal this was/is not enough.
I created a Vue Table through uiBuilder where I can edit / add topic's to be monitored but now I would like to highlight the row of the device that goes offline for easier identification , should I have missed the notification.
This is what the interface looks like
How do I achieve this? From my understanding I should use use computed properties but I just can get the hang of it.
Here is the .js code
/* jshint browser: true, esversion: 5, asi: true */
/*globals Vue, uibuilder */
// @ts-nocheck
/*
Copyright (c) 2021 Julian Knight (Totally Information)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict'
/** @see https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Front-End-Library---available-properties-and-methods */
// eslint-disable-next-line no-unused-vars
new Vue({
el: '#app',
data: {
// return {
fields: [
{ key: "id", label: "ID"},
{ key: "date", label: "Date Added" },
// { key: "updated", label: "Last Update" },
{ key: "name", label: "Name"},
{ key: "topic", label: "Monitor Topic" },
{ key: "timeout", label: "Time Out" ,sortable: true},
{ key: "status", label: "Status" ,sortable: true },
{ key: "recieved", label: "Last Trigger" },
{ key: 'edit', label: ''}
],
items: [
],
selectedRow: {},
// };
new_record:0,
}, // --- End of data --- //
methods: {
handleEditRow(data) {
//console.log(data.index);
// uibuilder.send({
// "payload": data.item,
// "index":data.index
// })
this.selectedRow = {
[data.index]: !this.selectedRow[data.index]
}
var edit = this.selectedRow[data.index];
//var old = context.old || "none"
if (edit == false){
uibuilder.send({
"payload": data.item,
"old":this.old,
"cmnd":"edit"
})
}else{
this.old = data.item ;
}
},
switchOn: function(name) {
//console.debug(event)
//console.log('Button Press name: %s; value: %s',name, this[name])
if (this[name] === false){
var stat = true;
}else{
var stat = false;
}
uibuilder.send({
"payload": {
"cmnd": name,
"value": stat,
// "type":'switch'
},
"cmnd":name
})
},
// },
}, // --- End of methods --- //
// Available hooks: beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed, activated,deactivated, errorCaptured
/** Called after the Vue app has been created. A good place to put startup code */
created: function() {
// Example of retrieving data from uibuilder
this.feVersion = uibuilder.get('version')
/** **REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3
* Pass the namespace and ioPath variables if hosting page is not in the instance root folder
* e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.
* e.g. uibuilder.start('/uib', '/uibuilder/vendor/socket.io') // change to use your paths/names
* @param {Object=|string=} namespace Optional. Object containing ref to vueApp, Object containing settings, or String IO Namespace override. changes self.ioNamespace from the default.
* @param {string=} ioPath Optional. changes self.ioPath from the default
* @param {Object=} vueApp Optional. Reference to the VueJS instance. Used for Vue extensions.
*/
uibuilder.start(this) // Single param passing vue app to allow Vue extensions to be used.
//console.log(this)
},
/** Called once all Vue component instances have been loaded and the virtual DOM built */
mounted: function(){
//console.debug('[indexjs:Vue.mounted] app mounted - setting up uibuilder watchers')
var app = this // Reference to `this` in case we need it for more complex functions
// If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO
// newVal relates to the attribute being listened to.
uibuilder.onChange('msg', function(msg){
console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)
app.items = msg.payload
})
} // --- End of mounted hook --- //
}) // --- End of app1 --- //
// EOF
and the index.html code
<!doctype html>
<html lang="en"><head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Device Tracker Page</title>
<meta name="description" content="Device Status Tracker">
<link rel="icon" href="./images/node-blue.ico">
<link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.css" />
<script type="text/javascript" src="http://192.168.8.30:1880/scripts/tabulator.min.js"></script>
<link href="http://192.168.8.30:1880/scripts/tabulator_semantic-ui.min.css" rel="stylesheet">
<!-- Your own CSS -->
<link type="text/css" rel="stylesheet" href="./index.css" media="all">
</head><body>
<!-- Your Site Start Here / -->
<div id="app" v-cloak>
<b-container fluid>
<h2>Device Tracker</h2>
<b-button v-on:click="switchOn('new_record')">Add Record</b-button>
<b-table striped hover small :items="items" :fields="fields">
<template #cell(name)="data">
<b-form-input v-if="selectedRow[data.index]" type="text" v-model="items[data.index].name"></b-form-input>
<span v-else>{{data.value}}</span>
</template>
<template #cell(topic)="data">
<b-form-input v-if="selectedRow[data.index]" type="text" v-model="items[data.index].topic"></b-form-input>
<span v-else>{{data.value}}</span>
</template>
<template #cell(timeout)="data">
<b-form-input v-if="selectedRow[data.index]" type="text" v-model="items[data.index].timeout"></b-form-input>
<span v-else>{{data.value}}</span>
</template>
<template #cell(recieved)="data">
<b-form-input v-if="selectedRow[data.index]" type="number" v-model="items[data.index].recieved"></b-form-input>
<span v-else>{{data.value}}</span>
</template>
<template #cell(status)="data">
<b-form-input v-if="selectedRow[data.index]" type="text" v-model="items[data.index].var4"></b-form-input>
<span v-else>{{data.value}}</span>
</template>
<template #cell(edit)="data">
<b-button size="sm" @click="handleEditRow(data)">
<span v-if="!selectedRow[data.index]">Edit</span>
<span v-else>Done</span>
</b-button>
</template>
</b-table>
<!-- Table Ends Here / -->
</div>
<!-- These MUST be in the right order. Note no leading / -->
<!-- REQUIRED: Socket.IO is loaded only once for all instances. Without this, you don't get a websocket connection -->
<script src="../uibuilder/vendor/socket.io/socket.io.js"></script>
<!-- Vendor Libraries - Load in the right order, use minified, production versions for speed -->
<script src="../uibuilder/vendor/vue/dist/vue.js"></script> <!-- dev version with component compiler -->
<!-- <script src="../uibuilder/vendor/vue/dist/vue.min.js"></script> prod version with component compiler -->
<!-- <script src="../uibuilder/vendor/vue/dist/vue.runtime.min.js"></script> prod version without component compiler -->
<script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js"></script> <!-- Dev version -->
<!-- <script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.min.js"></script> Prod version -->
<!-- REQUIRED: Sets up Socket listeners and the msg object -->
<script src="./uibuilderfe.js"></script> <!-- dev version -->
<!-- <script src="./uibuilderfe.min.js"></script> prod version -->
<!-- OPTIONAL: You probably want this. Put your custom code here -->
<script src="./index.js"></script>
</body></html>
any help / guidance will be much appreciated!