CSS/JS Image on-click change synchronized on multiple devices - javascript

I wanted to ask if it would be possible to do some script or css style for the fact that once I click on the image it will change to another. I found a lot like this, but I need it a little differently, I need to see the picture changed on one device when I click the picture on another device.
In the code I have an image type input and after clicking on the input I need to change the picture and remember the already changed value. So when I open the page on the new device, the image has already been changed.
<form method="get">
<input type="image" class="switch_img" src="switch_off.png" value="Zapnout" name="on1">
</form>
(The program works like switching off and on of LEDs. And I want the clicker to make the "animation" of the switch.)
I have the variables stored in the txt file in Raspberry, here is the part of the code that could theoretically be connected:
$fileName = __DIR__.'/txt/led2.txt';
if (!file_exists($fileName) || (file_get_contents($fileName) !== '1' && file_get_contents($fileName) !== '0')) {
file_put_contents($fileName, '1');
}
if (isset($_GET['on2']) && file_get_contents($fileName) === '1') {
shell_exec("/usr/local/bin/gpio -g write 15 1");
file_put_contents($fileName, '0');
}
else if (isset($_GET['on2']) && file_get_contents($fileName) === '0') {
shell_exec("/usr/local/bin/gpio -g write 15 0");
file_put_contents($fileName, '1');
}
Thanks for your help!

Projects like Vue, Vuetify and Axios make it easy to build out what you want with straightforward syntax, in just a few lines of "javascript".
<!DOCTYPE html>
<html>
<head>
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
<v-app>
<v-content>
<v-container>
<h4>My Switch/s</h4>
<v-alert type="error" :value="error">
{{ error }}
</v-alert>
<v-card v-for="(item, index) in switches" :key="index">
<v-card-title primary-title>
<div>
<div class="headline"></div>
<span class="grey--text">{{ item.name }}</span>
</div>
</v-card-title>
<v-card-text>
<v-switch v-model="item.state" :label="item.state ? 'On' : 'Off'" color="success" hide-details #click="setState(item)"></v-switch>
</v-card-text>
</v-card>
</v-container>
</v-content>
</v-app>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
//
var vm = new Vue({
el: '#app',
data: () => ({
error: false,
pollId: 0,
switches: [{
name: 'LED 1',
state: false
}
]
}),
beforeDestroy: function() {
clearInterval(this.pollId);
},
mounted: function() {
this.getState()
this.poll()
},
methods: {
poll() {
clearInterval(this.pollId)
this.pollId = setInterval(() => {
this.getState()
}, 2000)
},
async getState() {
try {
const response = await axios.get('/switch.php')
this.switches = response.data
} catch (error) {
this.error = error
}
},
async setState(item) {
item.state = !item.state
try {
await axios.post('/switch.php', item)
} catch (error) {
this.error = error
}
}
}
});
</script>
</body>
</html>
Then the PHP part (switch.php):
<?php
$switches = file_get_contents('switches.json');
// handle toggle
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// get json body
$body = (array) json_decode(file_get_contents('php://input'), true);
// toggle the switch
shell_exec('/usr/local/bin/gpio -g write 15 '.intval(!empty($body['state'])));
// set its current state
if (isset($switches[$body['name']])) {
$switches[$body['name']]['state'] = $body['state'];
} else {
$switches[$body['name']] = $body;
}
// save
file_put_contents('switches.json', json_encode($switches, JSON_PRETTY_PRINT));
header('HTTP/1.1 204 No content');
} else {
header('Content-Type: application/json');
echo json_encode($switches);
}
Untested but should point you in the right direction.

Related

Getting an error when trying to add a new block to EditorJS manually

Context
I've created a two column page, one column with a button on the left and editorJS on the right column.
What I am trying to do is whenever I click on the button to the left, I want it to be copied into a new block of EditorJS.
Replication
The error triggers whenever trying to add a new block manually (in this case, an extertal button to add more content to EditorJS) using editor.blocks.insert(blockToAdd). Independently of the configuration of the EditorJS, even the most basic one will trigger this error.
Code
index.js (I've modified this file to make it shorter, the error always trigger in the same place which is
const blockToAdd = {
type: 'paragraph',
data: {
text: 'My header'
}
};
editor.blocks.insert(blockToAdd); // Here
Actual file
const btn = document.getElementById('export-btn')
const editor = new EditorJS({
/**
* Id of Element that should contain Editor instance
*/
onReady: () => {
new DragDrop(editor);
},
holder: 'editorjs',
tools: {
header: {
class: Header,
config: {
placeholder: 'Enter a header',
levels: [1,2,3,4],
defaultLevel: 3
}
},
paragraph: {
class: Paragraph,
inlineToolbar: true,
}
},
});
function saveEditor() {
editor.save().then( savedData => {
fetch('http://localhost:3000', {
method: 'POST',
body: JSON.stringify(savedData),
headers: {
'Content-Type': 'application/json'
}
}).then( msg => {
console.log(msg)
}).catch( err => {
console.error(err)
})
console.log()
})
.catch( err => {
console.error(err)
})
}
btn.addEventListener('click', function() {
const blockToAdd = {
type: 'paragraph',
data: {
text: 'My header'
}
};
editor.blocks.insert(blockToAdd);
});
index.html
<!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.0">
<link rel="stylesheet" href="style.css">
<title>Testing EditorJS and Docx</title>
</head>
<body>
<div class="col-left">
<div id="export-btn" class="export-btn">Export to...</div>
</div>
<div class="col-right">
<div id="editorjs"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/#editorjs/editorjs#latest"></script>
<script src="https://cdn.jsdelivr.net/npm/#editorjs/header#latest"></script>
<script src="https://cdn.jsdelivr.net/npm/#editorjs/list#latest"></script>
<script src="index.js"></script>
</body>
</html>
Error
Uncaught TypeError: can't access property "name", s is undefined
S https://cdn.jsdelivr.net/npm/#editorjs/editorjs#latest:6
value https://cdn.jsdelivr.net/npm/#editorjs/editorjs#latest:6
value https://cdn.jsdelivr.net/npm/#editorjs/editorjs#latest:6
<anonymous> https://cdn.jsdelivr.net/npm/#editorjs/editorjs#latest:6
<anonymous> file:///E:/wdev/tasktag-dashboard-ui/index.js:105
EventListener.handleEvent* file:///E:/wdev/tasktag-dashboard-ui/index.js:97
editorjs#latest:6:44399
Error screenshot
Where could the problem be at? Because I am using <script src="https://cdn.jsdelivr.net/npm/editorjs-drag-drop#latest"></script> sort of imports?
Otherwise, I don't know what the problem is. Thank you in advance.
So the problem was in the object I pass to the editor.blocks.insert(blockToInsert).
It requires to pass option by option instead a single object. So the correct solution would be:
const blockToAdd = {
type: 'paragraph',
data: {
text: 'My header'
}
};
editor.blocks.insert(blockToAdd.type, blockToAdd.data);
Thanks Thomas from a JavaScript Telegram community for helping me out to resolve this problem.

Vue, can't get why it acting strange in a function. Runs 5 times forEach when there is a return

That's my whole test file. I've done so far, validation and it changes span class correctly due to correctly or not correctly fulfilled input. But where I'm stuck is I want disable button if there is not correctly fulfilled input or empty at all. And I think I've done logic right, but it doesn't work. I consoled.loged it, I see where is an issue, but why it happens for me is a mystery.
In short what happens: button is signed to variable button, and inputs on every input event calling function ft_button which check's if inputs are correctly fulfilled and buy that result it changes variable button. And it would have been fine, but in this function I don't know why it runs forEach cycle 5 times when there is return written. Is it some sort of JS thing? Cause in C if there is a return it stopps looping no matter what. And of course it will print out active at the end since it just skips all returns in forEach loop.
on pic you can see it logs 5 times 2 which is actually a surprise for me, cause after return it should just stop looping. Gmm how then should I return active or disabled...
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>1</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link href="css/styles.css" rel="stylesheet">
<script src="js/vue.js"></script>
</head>
<body>
<div class="wrapper">
<div class="sample">
<form>
<div class="progress">
<div class="progress-bar"></div>
</div>
<div>
<div class="form-group" v-for="v in info">
<label v-bind:for='v.name'>{{ v.name | capitalize }}</label><span :class="alertType(v.value)"></span>
<input id="intra" type="text" class="form-control" v-on:input="checkInput($event, v)">
<div>{{ v.value ? 'true' : 'false'}}</div>
</div>
</div>
<button class="btn btn-primary" :class="button">
Send Data
</button>
</form>
<div>
<table class="table table-bordered">
<tr>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
</div>
<script>
Vue.filter('capitalize', function (value) {
if (!value) return '';
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
el: '.sample',
data: {
button: 'disabled',
info: [
{
name: 'intra',
value: '',
pattern: /^[a-zA-Z ]{2,30}$/
},
{
name: 'phone',
value: '',
pattern: /^[0-9]{7,14}$/
},
{
name: 'email',
value: '',
pattern: /.+/
},
{
name: 'password',
value: '',
pattern: /.+/
},
{
name: 'repeatPassword',
value: '',
pattern: /.+/
}
]
},
methods:
{
checkInput(e, obj){
obj.value = obj.pattern.test(e.target.value);
this.button = this.ft_button();
},
alertType(value)
{
if(value === true)
return "fa fa-check-circle";
if(value === false)
return "fa fa-exclamation-circle";
},
ft_button()
{
this.info.forEach((el) =>
{
if (el.value === false || el.value === '')
{
console.log(2);
return 'disabled';
}
})
console.log(1);
return 'active';
}
},
computed:
{
}
});
</script>
</body>
</html>
you can't return from forEach the same way you can in a vanilla for loop. This question may be helpful: What does `return` keyword mean inside `forEach` function?

After array items loop, re-loop them again with new data using a timer

I have a very simple v-for array loop that grabs data from Axios and displays it in a newsreel that will show each news item, one after another, automatically. This works great, but after a few minutes it runs out of items and shows a blank div since there are only about 30 news items on the API.
What I need
After the v-for array runs out of items I simply want to re-run it. Fetch the API (since the API items change every 30 seconds) and then re-run the v-for array without the user having to refresh the page.
Axios call which is shown below
axios.get('https://myapi/news_list')
.then(response => {
this.news = response.data
});
Template
<ul class="news-reel">
<li v-for="name in news">
<a :href="name.url">{{name.title}}</a>
</li>
</ul>
** EDIT **
When I say it shows each item automatically, the ul just has a class animation that scrolls (or slides) the news items like a news marquee reel. That's all.
You could use a timer that you initialize it in created hook like :
created(){
setInterval(()=>{
axios.get('https://myapi/news_list')
.then(response => {
this.news = response.data
});
},30000);
}
Full example for simualation
new Vue({
el: '#app',
data() {
return {
news: [],
index: 0
}
},
computed: {
cptNews() {
return this.news.map((n, i) => {
let t = n;
t.id = i;
return t;
})
}
},
created() {
setInterval(() => {
let n = {};
n.title = "News " + this.index;
n.url = "https://myapi/news_list/" + this.index;
this.news.push(n)
this.index++;
}, 4000);
}
});
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Vue.delete">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.min.js"></script>
</head>
<body>
<div id="app">
<ul class="news-reel">
<li v-for="name in cptNews">
<span>{{name.id}}</span>
<a :href="name.url">{{name.title}}</a>
</li>
</ul>
</div>
</body>
Your code should be like this (no need to mounted):
data() {
return {
news: []
};
},
created() {
setInterval(() => {
axios.get('https://myapi.co/news/')
.then(response => {
this.news = response.data.data
});
}, 4000);
}

Modify the javascript to load on window load

Here is a javascript on "Speech to text recognition".The script runs on click.But I want to run the script on window/page load.I am not actually a javascript guy.Would you please help me to modify the script?
Extra[not essential to answer]: additionally I would like to modify the html code into simple html code from the existing "Vuitify" format.Can you help?
Note:Here I've addded the "snippet" that only will work on 'Goggle Crome' browser.
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
var recognition = SpeechRecognition ? new SpeechRecognition() : false;
Vue.component('speech-to-text', {
template: '\n <v-card>\n <v-card-text>\n <v-layout row wrap justify-space-around>\n <v-flex xs8 sm9 text-xs-center>\n <p v-if="error" class="grey--text">{{error}}</p>\n <p v-else class="mb-0">\n <span v-if="sentences.length > 0" v-for="sentence in sentences">{{sentence}}. </span>\n <span>{{runtimeTranscription}}</span>\n </p>\n </v-flex>\n <v-flex xs2 sm1 text-xs-center>\n <v-btn\n dark\n #click.stop="toggle ? endSpeechRecognition() : startSpeechRecognition()"\n icon\n :color="!toggle ? \'grey\' : (speaking ? \'red\' : \'red darken-3\')"\n :class="{\'animated infinite pulse\': toggle}"\n >\n <v-icon>{{toggle ? \'mic_off\' : \'mic\'}}</v-icon>\n </v-btn>\n </v-flex>\n </v-layout>\n </v-card-text>\n </v-card>\n ',
props: {
lang: {
type: String,
default: 'en-US' },
text: {
type: [String, null],
required: true } },
data: function data() {
return {
error: false,
speaking: false,
toggle: false,
runtimeTranscription: '',
sentences: [] };
},
methods: {
checkCompatibility: function checkCompatibility() {
if (!recognition) {
this.error = 'Speech Recognition is not available on this browser. Please use Chrome or Firefox';
}
},
endSpeechRecognition: function endSpeechRecognition() {
recognition.stop();
this.toggle = false;
this.$emit('speechend', {
sentences: this.sentences,
text: this.sentences.join('. ') });
},
startSpeechRecognition: function startSpeechRecognition() {var _this = this;
if (!recognition) {
this.error = 'Speech Recognition is not available on this browser. Please use Chrome or Firefox';
return false;
}
this.toggle = true;
recognition.lang = this.lang;
recognition.interimResults = true;
recognition.addEventListener('speechstart', function (event) {
_this.speaking = true;
});
recognition.addEventListener('speechend', function (event) {
_this.speaking = false;
});
recognition.addEventListener('result', function (event) {
var text = Array.from(event.results).map(function (result) {return result[0]; }).map(function (result) {return result.transcript; }).join('');
_this.runtimeTranscription = text;
});
recognition.addEventListener('end', function () {
if (_this.runtimeTranscription !== '') {
_this.sentences.push(_this.capitalizeFirstLetter(_this.runtimeTranscription));
_this.$emit('update:text', '' + _this.text + _this.sentences.slice( - 1)[0] + '. ');
}
_this.runtimeTranscription = '';
recognition.stop();
if (_this.toggle) {
// keep it going.
recognition.start();
}
});
recognition.start();
},
capitalizeFirstLetter: function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
} },
mounted: function mounted() {
this.checkCompatibility();
} });
new Vue({
el: '#app',
data: function data() {
return {
text: '',
sentences: null };
},
methods: {
speechEnd: function speechEnd(_ref) {var sentences = _ref.sentences, text = _ref.text;
console.log('text', text);
console.log('sentences', sentences);
this.sentences = sentences;
} } });
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'>
<link rel='stylesheet' href='https://unpkg.com/vuetify#1.0.17/dist/vuetify.min.css'>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/animate.css#3.5.2/animate.min.css'>
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-layout row wrap justify-center class="mt-4">
<v-flex xs12 sm10 text-xs-center>
<v-text-field name="x"
label="The text"
v-model="text"
textarea
></v-text-field>
</v-flex>
<v-flex xs12 sm8 md4 text-xs-center>
<speech-to-text :text.sync="text" #speechend="speechEnd"></speech-to-text>
</v-flex>
<v-flex xs12 text-xs-center class="mt-4">
{{sentences}}
</v-flex>
</v-layout>
</v-container>
</v-app>
</div>
<script src='https://unpkg.com/babel-polyfill/dist/polyfill.min.js'></script>
<script src='https://unpkg.com/vue/dist/vue.js'></script>
<script src='https://unpkg.com/vuetify#1.0.17/dist/vuetify.min.js'></script>
You can wrap the JavaScript code into a function and call the wrapped function on body onload using <body onload="wrappedFunction();">
Make sure your scripts/dependencies are loaded before this. You can add the scripts in the <head>

VueJS api call leaving data undefined

I am learning VueJS 2.0 and I am connecting to an API where I want the value of some data to change on input change. Here is what the output says using the dev tools:
canadianDollar:undefined
europeanEuro:undefined
europeanPound:undefined
usd:"1232"
Whenever I put 1232 in the USD input field it doesn't return anything and leaves those properties as undefined. Here is the code.
new Vue({
el: '#app',
data: {
usd: '',
canadianDollar: '',
europeanPound: '',
europeanEuro: ''
},
// Watch methods
watch: {
usd: function() {
this.convertCurrency()
}
},
// Logic Methods
methods: {
convertCurrency: _.debounce(function() {
var app = this;
if (app.usd.length !== 0) {
// Show that the things are loading in.
app.canadianDollar = 'Searching...'
app.europeanPound = 'Searching...'
app.europeanEuro = 'Searching...'
console.log(app.usd)
axios.get("http://api.fixer.io/latest?base=USD&" + app.usd)
.then(function(response) {
app.canadianDollar = response.data.CAD
app.europeanPound = response.data.GBP
app.europeanEuro = response.data.EUR
})
.catch(function(error){
app.canadianDollar = "ERROR"
app.europeanPound = "ERROR"
app.europeanEuro = "ERROR"
})
}
}, 500)
}
})
and the HTML:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Vue</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" name="" value="" v-model="usd">
<ul>
<li>Canadian Dollar: {{canadianDollar}}</li>
<li>European Pound: {{europeanPound}}</li>
<li>European Euro: {{europeanEuro}}</li>
</ul>
</div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js" charset="utf-8"></script>
<script src="index.js" charset="utf-8"></script>
</body>
</html>
When I type in a number it does give me the "Searching" part but disappears and nothing shows up.
I would recommend changing
then(function(response) {
app.canadianDollar = response.data.CAD
app.europeanPound = response.data.GBP
app.europeanEuro = response.data.EUR
})
to
then(function(response) {
console.log(response);
})
that was you can see what is being returned.
Also, axios.get("http://api.fixer.io/latest?base=USD&" + app.usd) should probably have a name like vulue:axios.get("http://api.fixer.io/latest?base=USD&VALUE=" + app.usd), but you'll have to check their api to see what it is meant to be called.
...
response.data.rates.CAD;
you have
response.data.CAD;
...
app.canadianDollar = response.data.rates.CAD * app.usd;

Categories