Kanka Cookbook
My Links 🏷️
  • Welcome to the Kanka Cookbook
  • Guide to Summernote
  • General tips and tricks
  • External tools and scripts for Kanka
  • 🎨CSS
    • Introduction to campaign CSS
    • Dashboard customization
    • Styling tooltips
    • Adapting layout to context
  • 🛠️Plugin Creators
    • Character sheet creation guide
    • Generating tooltips
    • Localizing character sheets
    • Theme creation tips
    • JavaScript in character sheets
      • Exposing attributes and other entity information
      • Live-editing attributes via the API
      • Importing external libraries
  • 🧙Power Users
    • Extraordinary Tooltips User Guide
    • Using transclusion
    • Changing a Plugin Library template’s default values
Powered by GitBook
On this page

Was this helpful?

  1. Plugin Creators
  2. JavaScript in character sheets

Live-editing attributes via the API

Last updated 2 months ago

Was this helpful?

Using JavaScript, we can make our own live-editing functionality without the use of Blade’s @liveAttribute() method and Kanka’s standard modals. For instance, you can make checkboxes that immediately update the entity when ticked and unticked directly on the sheet. Here is a helpful wrapper function that assumes you use the attribute dump provided by my tutorial to locate the appropriate API URL.

// Wrapper function for updating attribute values through the API
function postLiveEdit (name, value) {
  axios.post(attributes[name].apis.update.url, new URLSearchParams({value: value})).then(res => {
    // Update the local value of the attribute in the dump
    attributes[name].value = value;
    
    /* Any additional processing can be done here, e.g. cascading changes to other parts of the sheet */
    
    // Notify user; for iframe-based transclusions, send it to the parent window
    let message = "<em>" + attributes[name].name.replace(/\[range:.*\]/g, "") + "</em> updated successfully";
    (document.querySelector(".toast-container")) ? window.showToast(message) : window.parent.showToast(message);
  }).catch(err => {
    // Notify user; for iframe-based transclusions, send it to the parent window
    let message = "Failed to update <em>" + attributes[name].name.replace(/\[range:.*\]/g, "") + "</em> (error code: " + err.status + ")";
    (document.querySelector(".toast-container")) ? window.showToast(message) : window.parent.showToast(message);
  });
}

Using this, you only need to provide a name (attribute slug) and value any time you wish to update an attribute. Here is an example from my Daggerheart character sheet, where I have groups of checkboxes wrapped in a div with a data-stat attribute that specifies the slug. My script runs through all such divs and creates an event listener on each of them:

// Watch live attribute containers to update their related attribute on change
document.querySelectorAll('.daggerheart [data-stat]').forEach( (liveAtt) => {
  let attributeName = liveAtt.dataset.stat;

  // React to clicks
  liveAtt.addEventListener("click", (event) => {
    let numTicked;
    
    /* A bunch of processing occurs here to determine the new value based on what exactly was clicked within the div */
    
    // Update server-side attribute
    postLiveEdit(attributeName, numTicked);
  });
});

You can also very easily create new attributes on the entity programmatically:

axios.post(attributeApis.all.url, {name: 'aaa', type_id: "3", value: "1"})

Likewise, you can easily delete an existing attribute with a simple post to the corresponding URL, should the need arise (though you should have a very good reason to do so):

axios.post(attributes.slug.apis.delete.url);

Watch this space for a way to live-update ability charges through the API.

Only the name is mandatory; see the for all possible parameters, such as each type_id.

🛠️
API docs
Axios API