Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Pedro Mendes 53 posts 258 karma points
    Aug 22, 2022 @ 11:36
    Pedro Mendes
    0

    Custom Grid Editor

    Hello all!

    I wanted to make a grid list custom editor using the new Grid Editor in Heartcore but I'm fairly new to web components and I'm not sure if my approach is the right one here..

    My editor goal: being able to create a list that may have a title on the left side. The list itself can be ordered or unordered.

    This is the component I've created

    import { LitElement, css, html } from 'https://cdn.jsdelivr.net/gh/lit/dist@2/all/lit-all.min.js'
    
    export default class extends LitElement {
      static properties = {
        value: { type: Object },
        editTitleActive: {type: Boolean},
        editListActive: {type: Boolean}
      }
    
      static styles = css`
      textarea {
        box-sizing: border-box;
        width: 100%;
        outline: 0;
        border: 0;
        resize: none;
      }
    
      .bulletContainer {
        margin-top: 15px;
        display: flex;
        width: 100%;
      }
    
      #editableTitle, #editableList {
        display: none;
      } 
    
      #bulletTitle {
        width: 30%;
      }
      `
      toggleList(){
        this.value.isOrdered = !this.value.isOrdered;
        this.renderList();
      }
    
      getListHtml(){
        let template = this.value.isOrdered ? `<ol>` : `<ul>`;
        for(let i = 0; i < this.value.bullets.length; i++){
          template += `<li>${this.value.bullets[i]}</li>`;
        }
        template += this.value.isOrdered ? `</ol>` : `</ul>`
        return template;
      }
    
      renderList(){
        let bullets = this.renderRoot.querySelector('#rawList');
        bullets.innerHTML = this.getListHtml();
      }
    
      editTitle(){
        let orderedCheckbox = this.renderRoot.querySelector('#listTypeToggle');
        let editTitleBtn = this.renderRoot.querySelector('#editTitle');
        let editBulletsBtn = this.renderRoot.querySelector('#editList');
        let editableTitle = this.renderRoot.querySelector('#editableTitle');
        let rawTitle = this.renderRoot.querySelector('#rawTitle');
    
        this.editTitleActive = !this.editTitleActive;
    
        if(this.editTitleActive){
          orderedCheckbox.disabled = true;
          editBulletsBtn.disabled = true;
          editTitleBtn.innerHTML = "Save";
          editableTitle.style.display = "inherit";
          rawTitle.style.display = "none";
          editableTitle.focus();
        }
        else {
          orderedCheckbox.disabled = false;
          editBulletsBtn.disabled = false;
          editTitleBtn.innerHTML = "Edit";
          editableTitle.style.display = "none";
          rawTitle.style.display = "inherit";
    
          this.value.title = editableTitle.value;
          rawTitle.innerHTML = this.value.title;
        }
      }
    
      editList(){
        let orderedCheckbox = this.renderRoot.querySelector('#listTypeToggle');
        let editTitleBtn = this.renderRoot.querySelector('#editTitle');
        let editBulletsBtn = this.renderRoot.querySelector('#editList');
        let editableList = this.renderRoot.querySelector('#editableList');
        let rawList = this.renderRoot.querySelector('#rawList');
    
        this.editListActive = !this.editListActive;
    
        if(this.editListActive){
          orderedCheckbox.disabled = true;
          editTitleBtn.disabled = true;
          editBulletsBtn.innerHTML = "Save";
          editableList.value = this.value.bullets.join('\n');
          editableList.style.display = "inherit";
          rawList.style.display = "none";
    
          editableList.focus();
        }
        else {
          this.value.bullets = editableList.value.split('\n').filter((el) => el);
    
          orderedCheckbox.disabled = false;
          editTitleBtn.disabled = false;
          editBulletsBtn.innerHTML = "Edit";
          editableList.style.display = "none";
          rawList.innerHTML = this.getListHtml();
          rawList.style.display = "inherit";
    
          this.value.list = editableList.value;
        }
      }
    
      firstUpdated(){
        this.editTitleActive = false;
        this.editListActive = false;
    
        if(this.value.title){;
          let editableTitle = this.renderRoot.querySelector('#editableTitle');
          let rawTitle = this.renderRoot.querySelector('#rawTitle');
    
          editableTitle.value = this.value.title;
          rawTitle.innerHTML = this.value.title;
        }
    
        if(this.value.isOrdered){
          let checkbox = this.renderRoot.querySelector('#listTypeToggle');
          checkbox.checked = true;
        }
    
        if(this.value.bullets){
          this.renderList();
        }
      }
    
      render() {
        if(this.value == undefined){
          this.value = {
              title: '',
              isOrdered: false,
              bullets: []
          }
        } 
    
        return html` 
        <div>
            <input id="listTypeToggle" type="checkbox" @click="${this.toggleList}">
            <label for="listTypeToggle">Ordered list</label>
        </div>
        <div class="bulletContainer">
            <div id="bulletTitle">
                <div id="rawTitle"></div>
                <textarea id="editableTitle" placeholder="Teste"></textarea>
                <button id="editTitle" @click="${this.editTitle}">Edit</button>
            </div>
            <div id="bulletList">
                <div id="rawList"></div>
                <textarea rows="${this.value.bullets.length}" id="editableList"></textarea>
                <button id="editList" @click="${this.editList}">Edit</button>
            </div>
        </div>
        `
      }
    }
    

    My questions:

    1) am I doing this right or completely wrong?

    2) is there a way to tell that a field is mandatory? I wanted the bullets to be mandatory if the editor is inserted into a grid. The title, on the other hand, is completely optional.

    Thank you all :)

    edit: please don't mind the ugly code, I was just looking for functionality

  • Pedro Mendes 53 posts 258 karma points
    Aug 26, 2022 @ 11:55
    Pedro Mendes
    0

    Ok, a little update. I've done some refactoring in the code and I'me happy with the component itself.

    Now, the mandatory field this, I wasn't able to acheive.

    I was expecting the JSON schema would help me with this so I've done it like this:

    {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "title": "Bullets",
        "description": "Bullets component",
        "type": "object",
        "properties": {
            "title": {
                "description": "Optional title of the bullets component.",
                "type": "string"
            },
            "isOrdered": {
                "description": "Whether the bullet list is ordered (true) or unordered (false).",
                "type": "bool"
            },
            "bullets": {
                "description": "The items in the bullets list.",
                "type": "array",
                "items": {
                    "type": "string"
                },
                "minItems": 1
            }
        },
        "required": [
            "bullets"
        ]
    }
    

    However, I can save the editor in the grid with an empty list (the bullets) field :\ Is this mandatory question unachievable??

Please Sign in or register to post replies

Write your reply to:

Draft