how to dynamically change the (svg) icon of a Kendo .UI toggleButton (R2 2023)?

1 Answer 698 Views
Button Toolbar
Frank
Top achievements
Rank 1
Iron
Frank asked on 23 Jun 2023, 02:19 PM

I'd like to show / hide or change the icon of a toggle button and currently struggle getting this to work after changing to the current version.

I had no problems with older versions (2019 / 2021).

What I'm trying to achieve ist something like

setOptions({icon: "check"})

and (re)render()

I also tried to take the road via kendo.ui.icon(element....) and kendo.html.renderButton / renderIcon but so far to no avail.

Any hint would be greatly appreciated.

 

Kind regards

 

Frank

 

1 Answer, 1 is accepted

Sort by
0
Frank
Top achievements
Rank 1
Iron
answered on 24 Jun 2023, 12:35 PM | edited on 26 Jun 2023, 01:22 PM

I'll try to answer my own question with a solution that I finally came up with. In case someone else needs it.

Mmimics the original behavior and procuces the same html. see kendo.html.button.js for reference.

Here less compact as it could be for better understanding and readability.

from within toggle():

// ...
toggle: function(e){                                                        
    // 2023-06-24                        
    let cClassAdd = e.checked ? "k-i-check" : "k-i-none",
        cClassRem = e.checked ? "k-i-none" : "k-i-check";  

    if (kendo.version < "2023.1.425"){  // <-- our switchnig version. YMMV
        e.target.find(".k-icon").removeClass(cClassRem).addClass(cClassAdd);                        

    } else {                            
        const 
            KBUTTONICON = "k-button-icon",
            oButton = this,                                 
            oIconOptions = {icon: "", iconClass: cClassAdd};

        let $IconEl = oButton.element.children("span.k-icon, span.k-svg-icon").first();    

        if ($IconEl.length < 1){  // or (!$IconEl[0])
            // this should not happen unless someone ripped the span out                                
            console.warn("Ooops... where is the icon?");
            $IconEl = $(kendo.ui.icon(oIconOptions)).prependTo(oButton.element); 
            $IconEl.addClass(KBUTTONICON);  // <-- here as given in the 'else'

        } else {
            // normal case
            kendo.ui.icon($IconEl, oIconOptions);
        }
    }
    // ...
}

 

Works from outside basicly the same way:. Just set

const oButton = $("#<ElementID>").data("kendoToggleButton");

Instead of the iconClass, You can use icon with the icon alias or the class name.

So these variants should work:


const oIconOptions = {icon: "", iconClass: "k-i-check"};

// or

const oIconOptions = {icon: "check", iconClass: ""};

// or 
const oIconOptions = {icon: "k-i-check", iconClass: ""};   // <-- kendo.ui.icon()  also looks for the classname 

the not used option could be omitted

 

 

 

 

 

 

 

Frank
Top achievements
Rank 1
Iron
commented on 24 Jun 2023, 10:38 PM

some additional information:

I now came across this document, that also has some valuable information:

https://docs.telerik.com/kendo-ui/styles-and-layout/sass-themes/font-icons-migration

You can read and/or set the default iconType. and adapt Your code accordingly  Our version 2023.1.425 still defaults to "font" where as 2023.2.606 already uses "svg" by default.

console.log(kendo.defaults.iconType)     // --> prints either "font" or "svg"

this can be set via

kendo.setDefaults('iconType', 'font');
// or
kendo.setDefaults('iconType', 'svg');
So my example above should rather check for this setting than for kendo.version

 

Georgi Denchev
Telerik team
commented on 28 Jun 2023, 07:59 AM

Hi, Frank,

Everything that you stated is correct.

One more approach that you can use to update the icon inside the `toggle` event is the following one:

        toggle: function(e) {
	  let checked = e.checked,
              iconElement;
          // default icon is "save"
          if(checked) {
            // Find the current icon <span>
            iconElement = e.sender.wrapper.find(".k-svg-i-save");
            // Update the icon
            kendo.ui.icon(iconElement, { icon: "pencil" });
          } else {
            // same as above
            iconElement = e.sender.wrapper.find(".k-svg-i-pencil");
            kendo.ui.icon(iconElement, { icon: "save" });
          }
        }

The kendo.ui.icon utility allows you to target the current icon `<span>` element and update it with a new one. There is no need to replace/append/remove the previous one.

Dojo

I prepared a small Dojo sample that you can examine:

https://dojo.telerik.com/@gdenchev/EfayukaY 

Best Regards,

Georgi

Frank
Top achievements
Rank 1
Iron
commented on 28 Jun 2023, 11:10 AM

Hi Georgi,

thanks for Your response!  Good to know, I was on the right track.

I am actually doing the same as You recommended. The stuff around it is just fallback behavior for font icons and overly careful error prevention. 

I have actually modified my post afterwards, but the portal said "saved for review" and did not update the content since. 

The new approach is to check for iconType instead of version like

if (!kendo.defaults.iconType || kendo.defaults.iconType == "font"){
    // --> font icons
}  else {
   // --> svg icons
}

We're currently migrating to the new version and unless we're sure everything works with the new version as expected, I'll have to be able to handle both variants.

Your code works fine if everything is as expected (and as a functional demo). 

I like the e.sender.wrapper.find().. approach.

However, if for some reason the icon is not set as expected  it will trigger an "Uncaught TypeError: i.element[0] is undefined" error.

So in real life, I'd probably cushion it a bit by checkiing the existance of the iconElement or even force the coming up icon to be the desired one. 

This would be a bit more fail proof and works fine:


$("#button").kendoToggleButton({
    toggle: function(e) {
        let checked = e.checked,
            iconElement;
          
        // works if the correct icon is set:
        // iconElement = e.sender.wrapper.find(checked ? ".k-svg-i-save": ".k-svg-i-pencil");

        // but this finds the icon element regardless of the current icon
        iconElement = e.sender.wrapper.find("span.k-svg-icon");
                    
        if (iconElement.length > 0){
           kendo.ui.icon(iconElement, { icon: (checked ? "pencil" : "save") });
        }  
    },
    icon: "check"   // <-- initialize with a "wrong" icon. 
});

 

Have a great day!

 

Frank

 

 

 

 

 

 


 

Georgi Denchev
Telerik team
commented on 03 Jul 2023, 07:48 AM

Hi, Frank,

You're absolutely correct that it is better to have an additional check to ensure the item exists.

One more thing that I forgot to mention is that the `kendo.ui.icon` method will work for both SVG and Font icons.

With SVG it will replace the classes alongside the svg itself.

With Font icons, it will simply replace the classes on the element. So no matter which icon type you use, you can still utilize the method.

Dojo

https://dojo.telerik.com/@gdenchev/UpAWIhoc 

Best Regards,

Georgi

Frank
Top achievements
Rank 1
Iron
commented on 06 Jul 2023, 10:58 PM

Georgi,

thanks for the tip and the dojo.

I guessed that, but good to have it confirmed.

Have a great weekend!

Regards

Frank

 

 

Tags
Button Toolbar
Asked by
Frank
Top achievements
Rank 1
Iron
Answers by
Frank
Top achievements
Rank 1
Iron
Share this question
or