There are buttons on a page, each corresponding to a different code that needs to be sent to PubNub DSN, which is published to my home server to operate specific on/off commands for various lights in home. This is primarily a learning experience for now.
I currently have 4 basic buttons on page:
<section id="main" role="main">
<button type="button" name="d_on">Dining Room On</button>
<button type="button" name="d_off">Dining Room Off</button>
<button type="button" name="a_on">Bedroom On</button>
<button type="button" name="a_off">Bedroom Off</button>
</section>
NOTE: "Name is the code that needs to be sent, depending on which button is clicked, corresponding to the specific device"
Here is all the JavaScript I built to make it work. This was pretty easy and works perfectly:
<script src="https://cdn.pubnub.com/pubnub-3.15.2.min.js"></script>
<script>
(function(){
//DOM
var button1 = document.querySelector('button[name=d_on]');
var button2 = document.querySelector('button[name=d_off]');
var button3 = document.querySelector('button[name=a_on]');
var button4 = document.querySelector('button[name=a_off]');
var code1 = button1.name;
var code2 = button2.name;
var code3 = button3.name;
var code4 = button4.name;
// PubNub Channel Name
var channel = 'demo';
//Init - Sub and Pub key
var p = PUBNUB.init({
subscribe_key: 'sub-c...',
publish_key: 'pub-c...'
});
// Sending data
function jetson1(){
p.publish({
channel : channel,
message : {"text":"From Website",
"code": button1.name}
});
}
function jetson2(){
p.publish({
channel : channel,
message : {"text":"From Website",
"code": button2.name}
});
}
function jetson3(){
p.publish({
channel : channel,
message : {"text":"From Website",
"code": button3.name}
});
}
function jetson4(){
p.publish({
channel : channel,
message : {"text":"From Website",
"code": button4.name}
});
}
//Click event
button1.addEventListener('click',jetson1);
button2.addEventListener('click',jetson2);
button3.addEventListener('click',jetson3);
button4.addEventListener('click',jetson4);
})();
</script>
Problem is, while this works, it is very wordy and is only for 2 devices. I plan on adding many more and need a way to essentially only add the button and name attribute. The function then dynamically sends what it needs to.
I have worked on different things for hours and hours trying to get my head around the logic and syntax and can't seem to figure it out.
For example, I used the following and can get an array of the codes, but am stuck on what I could even do with this and think I may be making it more complicated than necessary. I appreciate any nudges to get my brain thinking in the right direction.
var buttons = document.querySelectorAll('button');
var code = new createCodes();
function createCodes(){
var code = []
for (var i = 0, len = buttons.length; i < len; i++) {
code[i] = buttons[i].name;
}
return code;
}
Researching a bit further, I tried to build the click events like so, but the problem is that it doesn't wait for the actual button click, they all fire at page load and then after that, the buttons do not respond to a click any longer.
(function(){
// PubNub Channel Name
var channel = 'demo';
//Init - Sub and Pub key
var p = PUBNUB.init({
subscribe_key: 'sub-c-',
publish_key: 'pub-c'
});
// Sending data
function jetson(code){
p.publish({
channel : channel,
message : {"text":"From Website",
"code": code}
});
}
var $ = function (selector) {
return document.querySelector(selector);
};
var buttons = $('#main').getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
var code = button.name;
button.onclick = jetson(code);
}
})();
</script>
1 Answer 1
(削除) You're on the right track, but you need to use jquery more effectively. (削除ここまで) I'm sorry, I thought you were already using jQuery. I see now that you have your own little homegrown jQuery-like function. You should just use jQuery instead, and that'll make this a lot easier.
Once you've added jQuery, then just by adding a class to the buttons you want this to happen on, and then binding an onclick event handler to that class you can remove all of your code duplication. As a note, you might not be able to run the stack snippet - I was getting some errors about XSS issues, but I have a weird browser configuration so I don't know if it'll affect you.
(function(){
var pubnubChannelName = 'demo'
var p = PUBNUB.init({
subscribe_key: 'sub-c...',
publish_key: 'pub-c...'
});
function publishData(code) {
p.publish({
channel: pubnubChannelName,
message: {
"text": "From Website",
"code": code
}
});
}
$(document).ready(function() {
$('.pubnub_button').click(function() {
publishData($(this).attr('name'));
});
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.pubnub.com/pubnub-3.15.2.min.js"></script>
<section id="main" role="main">
<button type="button" class='pubnub_button' name="d_on">Dining Room On</button>
<button type="button" class='pubnub_button' name="d_off">Dining Room Off</button>
<button type="button" class='pubnub_button' name="a_on">Bedroom On</button>
<button type="button" class='pubnub_button' name="a_off">Bedroom Off</button>
</section>
If you're going to continue to add more of these, however, you're probably going to want some dynamically generated HTML. The specifics of that are beyond the scope of this question, but I encourage you to look into those solutions as this project expands.
At times it is also desirable to not use any external libraries if possible, and I'm a firm believer that knowing how to do something in pure JavaScript (not just jQuery) is important. I also think that in many cases, adding jQuery as a dependency is unnecessary. Here you can easily accomplish the same thing in an almost identical fashion without adding jQuery. You'll notice that I actually had to change very little about your code - I just assigned the onclick event to an actual function, and I cleaned up a bit towards the end.
(function() {
var channel = 'demo';
var p = PUBNUB.init({
subscribe_key: 'sub-c-',
publish_key: 'pub-c'
});
function jetson(code) {
p.publish({
channel: channel,
message: {
"text": "From Website",
"code": code
}
});
}
var $ = function(selector) {
return document.querySelectorAll(selector);
};
var buttons = $('#main > button');
for (var button in buttons) {
button.onclick = function() {
jetson(button.getAttribute('name'));
};
}
})();
-
\$\begingroup\$ This was exactly what I was looking for! I knew it could be done as easy as this, but it is sometimes hard to put your finger on it and know what direction to take when you are still new. As the internet grows, and information is abundant, its easy to get lost in some fancy solutions. You are right, it wasn't jQuery I was using, was actually using some samples from a tutorial on the subject and that is what he did. Thought it was weird, but went with it. On another note, I am curious as to why what I had at the end of my initial post caused my click events to fire immediately? \$\endgroup\$shelzmike– shelzmike2016年07月16日 22:28:37 +00:00Commented Jul 16, 2016 at 22:28
-
1\$\begingroup\$ @shelzmike The line
button.onclick = jetson(code);
is assigningbutton.onclick
to the return value ofjetson(code)
. You probably wanted something likebutton.onclick = function() { return jetson(code); };
. You assign it an anonymous function that closes over the current values ofjetson
andcode
. \$\endgroup\$Dan Oberlam– Dan Oberlam2016年07月16日 23:04:53 +00:00Commented Jul 16, 2016 at 23:04 -
1\$\begingroup\$ @shelzmike to answer your question, it's because of this line
button.onclick = jetson(code);
that will NOT make the click event firejetson(code)
, instead the function is invoked and the result (which isundefined
) is assigned to the click handler. Hence why everything gets executed on page load. One way is avoid this is to wrap it in a function at the point of assigning, e.g.,button.onclick = function() { jetson(code); };
- that way clicking the button invokes the anonymous function which itself has the context needed. \$\endgroup\$VLAZ– VLAZ2016年07月16日 23:05:14 +00:00Commented Jul 16, 2016 at 23:05 -
\$\begingroup\$ That makes sense now. It has been so long since I worked with Javascript, I forgot all about that. (If I recall, I had a problem very similar back when). Thanks to both for the clarification. \$\endgroup\$shelzmike– shelzmike2016年07月18日 04:51:07 +00:00Commented Jul 18, 2016 at 4:51