Ui_template mvc and scope of context/flow/global stores

Sorry all I am struggling over basic stuff.

I have a checkbox based toggle button which toggles between the two states when clicked.

<md-button class="md-button remote-button3x bigger" 
    data-payload="1" 
    data-buttontype="checkbox"
    data-topic="10"
    >
    <label class="remote-button3x-switch">
        <input type="checkbox" id="10">
        <div class="remote-button3x-slider round">
            <span class="remote-button3x-on">O-N</span><span class="remote-button3x-off">O-F-F</span>
        </div>
    </label>       
</md-button>

I can addClass, toggleClass and removeClass using example code you provided.

How do I select and set the text content of the two classes "remote-button3x-on" and "remote-button3x-off" ?

w3s shows $("#test1").text("Hello world!"); which is not getting me anywhere.

I have added:

            case "setContent":
                $btn.text("Hello world!");
              //  $btn.toggleClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value
                break;

but have no clue how to set content for class remote-button3x-on & remote-button3x-off.

hard to tell without seeing what kind of changes you have made in "script for all buttons with class remote-button" .
As it states, functionality deals with elements which have defined class remote-button. You have created an element with class remote-button3x, so it will be ignored. Also you want to change content of nested element which again has different class.
There is no magic.
W3s shows correctly - $("#test1").text("Hello world!") -> select element with id test1 and set it's text Hello world!
That is the basics.
In your case it should be -> select element with class remote-button3x-on and set it's text to Hello world!

Originally there was selector for class .remote-button and to find specific element, the data-topic must match with the msg.topic

var BUTTON_CLASS = ".remote-button";
...
var buttonSelector =  BUTTON_CLASS + "[data-topic='" + msg.topic + "']"

So if your elements can not be selected, you'll need to adjust something. Even to make selector rules smarter or make your elements to follow the selector rules.

Thanks. I had already altered your code to target BUTTON_CLASS=.remote-button3x in place of .remote-button. Also all the places where you target buttontype=toggle I added equivalent code to target buttontype=checkbox and it is from here that I am stuck.

This is where I am now. I have tried lots of selector rules but cannot figure out how to change the content of these two spans ?

After that I need to figure out how to set the state. To isolate my attempts I have added:

            case "setContent":
                $btn.text("Hello world!");
              //  $btn.toggleClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value
                break;

to processCommand().

To identify what is the element you actually selected, do this. It logs out names classes for that element. If those are what you are looking for, you are good with selecting the element.

case "setContent":
console.log($btn.attr("class"));
break

And if that selected element is span, the $btn.text("Hello world!"); should work fine.

I get

md-button remote-button3x bigger md-button md-ink-ripple

not sure why md-button is in there twice ?

So you have selected what is marked with red.
image

But you want to select what is marked with yellow. So the rules must be somehow different.
Again, the functionality is created for elements which are created in specific way. Your button is built differently. I can't still say what you need to change. Even how the button is built or the rules.

You can make the selector rule to be part of incoming payload.

var buttonSelector =  BUTTON_CLASS + "[data-topic='" + msg.topic + "']"
        if(typeof msg.payload === "object" && msg.payload.selector){
            buttonSelector = msg.payload.selector 
        }

And send then the payload like this


{"selector":".remote-button3x-on","command":"setContent","value":"HELLO"}

Will it fit into your project logic, I can't really tell ..

That looks like a wonderful idea thank you.

My project logic is to create a button with:

  1. Type toggle radio momentary

  2. Provide easy & efficient access to button text class state

  3. Provide a level of user branding

  4. Be persistent across browser refresh, node-red restarts/power failure.

Your initial example (of which I am truly grateful it has been incredibly illuminating) covered 1. completely ok,
2. all except text (at the beginning I did not have a styled button that exposed the on/off text, I only had an icon example). I am in the process of trying to style a button with both.
3. completely ok.
4. todo.

Can I confirm that this is all I need ?

msg is {"selector":".remote-button3x-on","command":"setContent","value":"HELLO"}

var buttonSelector =  BUTTON_CLASS + "[data-topic='" + msg.topic + "']"
        if(typeof msg.payload === "object" && msg.payload.selector){
            buttonSelector = msg.payload.selector 
            $(buttonSelector).text(msg.value);
        }

That gives you the option to target any element if you know the name of it's class or id.
"selector":".remote-button3x-on" selects element with class remote-button3x-on
"selector":"#my-element" selects element with id my-element

So basically you have freedom to select anything. What you will do with selected element, it's up to you. As far you are doing what is possible in terms of html, jquery, css ....

would this select all buttons with class=.remote-button3x-on ?

Of course. :slight_smile:

The button I need to select is defined in msg.topic. I cannot figure out the selector that does both.

A useful broadcast type use case however.

As the main selector rule looks button uniqueness from data-topic, I think it will be reasonable to use same logic..

var buttonSelector =  BUTTON_CLASS + "[data-topic='" + msg.topic + "']"
if(typeof msg.payload === "object" && msg.payload.selector){
            buttonSelector = msg.payload.selector + "[data-topic='" + msg.topic + "']"
}

And in your buttons the elements you'll need to reach must also have data-topic defined.

...
<div class="remote-button3x-slider round">
     <span class="remote-button3x-on" data-topic="10">

there is more ways to do it of course but ...

A nice place to explore selector tricks http://www-db.deis.unibo.it/courses/TW/DOCS/w3schools/jquery/trysel.asp.html

I see. It is no problem adding data-topic="10" to the span classes but... what ?

I suppose it is not so good if a user has to make many edits to "data-topic='x'" in order to make the instance unique.

Just a thing that is niggling me a bit. If I can select the button uniquely through

        var buttonSelector =  BUTTON_CLASS + "[data-topic='" + msg.topic + "']" 
        var $btn = $(buttonSelector);//get the button

Why can I not select from within the context of $btn the '.remote-button-3x-on' class text ?

Also I thought I saw a w3s example of something where if one had

class='class1-subclass1' and class='class1-subclass2' ...

that there was a group selector syntax like |- (read or) so what is returned are all elements whose class name ends with '-subclassX' but within 'class1' scope ?

I really struggle with my description sorry.

Is something like this possible:
If you can do this $(".remote-button3x-on", this) can I do something akin to
$(".remote-button3x-on", $btnscope) ?

Yes you can use the jquery find() to find elements inside the button
var someElement = $btn.find(msg.payload.selector)

At a cost I suppose. I am trying to avoid unnecessary uses of 'find' since I can predict the html structure so I tried to use something like $(this).children(".remote-button3x-on") where this is the $btn selected with BUTTON_CLASS + "[data-topic='" + msg.topic + "']"

But I get $(...).children is not a function in the console.
Edit: Sorry found a typo. It actually returns undefined.

works well. I cant see any cost issue here..??

Is the find done within the context of the button ?

Unfortunately it returns undefined.

Any idea what; ARIA: Attribute " aria-label ", required for accessibility is doing in my console ?

do console.log(msg.payload.seletor) and see if it is correct thing to search in the button.

var spanSelectorOn =  ".remote-button3x-on"; 
var $spanOn = $($btn).find(spanSelectorOn);//get the span
console.log("$spanOn=" + $spanOn.attr("text"));

returns undefined

console.log("$spanOn=" + $spanOn.text);

returns:-
$spanOn=function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)}

which is beyond me I am sorry to say.