Bug refreshing list/grid adding elements in between existing documents

I have been digging in this issue since I discover the behavior not refreshing properly a list/grid when adding new elements to a collection in Firebase. I create a new post since I have created a really simple project from scratch in order to isolate the issue and solve. This would be very important for me as it is quite difficult to add documents to the database as I have the lists right now as I have to be constantly refreshing.

So the issue shows always when you have a list/grid with several components and you want to add an element in the beginning of the list or in between existing documents. That would have to refresh and reallocate the existing documents, and in that process things get mixed. There is no problem if you add elements at the end of the list. Here it is a video I have recorded of the issue:


I have uploaded the project linked to a testProject in my Firestore in the link:
You can try to add elements and see how it behaves. My project is is just one Screen that shows a list/grid based on the dataSheet that has the column “names” and the column “usernames” as well as two icons: edit and delete. There is a component to add those two fields and an icon to refresh the list but it does nothing to fix the issue. The code glance for the screen is:
import React, { Component } from 'react';
import './App.css';
import TestList from './TestList';
import AddTestData from './AddTestData';
import btn_icon_924705 from './images/btn_icon_924705.png';

// UI framework component imports
import Button from 'muicss/lib/react/button';
import Appbar from 'muicss/lib/react/appbar';

export default class StartScreen extends Component {

  // Properties used by this component:
  // appActions, deviceInfo

  constructor(props) {
    super(props);
    
    this.state = {
      elAddTestData_visible: true,
    };
  }

  componentDidMount() {
    {
      let dataSheet = this.props.appActions.dataSheets['sheet1'];
      let serviceOptions = this.props.appActions.serviceOptions_sheet1;
      if ( !this.props.appActions.dataSheetLoaded['sheet1']) {
        serviceOptions.servicePath = dataSheet.expandSlotTemplateString("users", this.props.appActions.dataSlots);
        this.props.appActions.loadData_firebase1(dataSheet, serviceOptions, true);
        this.props.appActions.dataSheetLoaded['sheet1'] = true;
      }
    }
  }

  componentWillUnmount() {
  }

  componentDidUpdate() {
  }

  onClick_elFab = (ev) => {
    this.setState({elAddTestData_visible: !this.state.elAddTestData_visible});
  
  }
  
  
  render() {
    let layoutFlowStyle = {};
    let baseStyle = {};
    if (this.props.transitionId && this.props.transitionId.length > 0 && this.props.atTopOfScreenStack && this.props.transitionForward) {
      baseStyle.animation = '0.25s ease-in-out '+this.props.transitionId;
    }
    if ( !this.props.atTopOfScreenStack) {
      layoutFlowStyle.height = '100vh';
      layoutFlowStyle.overflow = 'hidden';
    }
    
    // eslint-disable-next-line
    const dataSheet_sheet1 = this.props.dataSheets['sheet1'];
    const style_elBackground = {
      width: '100%',
      height: '100%',
     };
    const style_elBackground_outer = {
      backgroundColor: '#f6f6f6',
     };
    
    // Source items and any special components used for list/grid element 'list'.
    let items_list = [];
    let listComps_list = {};
    items_list = items_list.concat(this.props.appActions.getDataSheet('sheet1').items);
    this._elList_items = [];
    
    const style_elList = {
      height: 'auto',  // This element is in scroll flow
     };
    const elAddTestData = this.state.elAddTestData_visible ? (
      <div className="hasNestedComps elAddTestData">
        <div>
          <AddTestData ref={(el)=> this._elAddTestData = el} appActions={this.props.appActions} deviceInfo={this.props.deviceInfo} locStrings={this.props.locStrings} />
        </div>
      </div>
      
     ) : null;
    
    const style_elFab = {
      display: 'block',
      color: '(null)',
      textAlign: 'left',
      cursor: 'pointer',
      pointerEvents: 'auto',
     };
    
    return (
      <div className="AppScreen StartScreen" style={baseStyle}>
        <div className="background">
          <div className="containerMinHeight elBackground" style={style_elBackground_outer}>
            <div className="appBg" style={style_elBackground} />
          </div>
        </div>
        
        <div className="layoutFlow" style={layoutFlowStyle}>
          <div className="hasNestedComps elList">
            <ul style={style_elList}>
              {items_list.map((row, index) => {
                let itemComp = (row._componentId)
                    ? listComps_list[row._componentId]
                    : <TestList appActions={this.props.appActions} deviceInfo={this.props.deviceInfo} locStrings={this.props.locStrings} dataSheetId={'sheet1'} dataSheetRow={row} {...{ 'name': row['name'], 'userEmail': row['userEmail'], }} ref={(el) => {if (el) this._elList_items.push(el)}} />;
                return (<li key={row.key}>
                    {itemComp}
                  </li>);
              })}
              <div className="marker" ref={(el)=> this._elList_endMarker = el} />
            </ul>
          </div>
          
          { elAddTestData }
        </div>
        <Appbar className="navBar">
          <div className="title">Start</div>  <div className="backBtn" onClick={ (ev)=>{ this.props.appActions.goBack() } }></div>
        </Appbar>
        
        <div className="screenFgContainer">
          <div className="foreground">
            <Button className="actionFont elFab" style={style_elFab}  variant="fab" color="accent" onClick={this.onClick_elFab} >
              <img src={btn_icon_924705} alt="" style={{width: '100%', marginTop: '4%'}} />
            </Button>
          </div>
        </div>
      </div>
    )
  }
  
}

And the code glance for the component for each document in the list is:

import React, { Component } from 'react';
import './App.css';
import btn_icon_456139 from './images/btn_icon_456139.png';
import btn_icon_20565 from './images/btn_icon_20565.png';

export default class TestList extends Component {

  // Properties used by this component:
  // name, userEmail

  constructor(props) {
    super(props);
    
    this.state = {
      testName: this.props.name || '',
      testuserEmail: this.props.userEmail || '',
    };
  }

  componentDidMount() {
  }

  componentWillUnmount() {
  }

  componentDidUpdate() {
  }

  onClick_elIconButton2 = (ev) => {
    // Remove row from connected sheet
    this.props.appActions.removeFromDataSheet(this.props.dataSheetId, this.props.dataSheetRow);
  
  }
  
  
  onClick_elIconButton = (ev) => {
    this.sendData_elIconButton_to_sheet1();
  
  }
  
  
  textInputChanged_elTestName = (event) => {
    this.setState({testName: event.target.value});
  }
  
  textInputChanged_elTestuserEmail = (event) => {
    this.setState({testuserEmail: event.target.value});
  }
  
  sendData_elIconButton_to_sheet1 = () => {
    const dataSheet = this.props.appActions.getDataSheet('sheet1');
  
    let row = this.props.dataSheetRow || {
      "name": this.props.name,
      "userEmail": this.props.userEmail,
    };
    row = { ...row, 
      name: this.state.testName,
      document_key: this.state.testName,
      userEmail: this.state.testuserEmail,
    };
    if (this.props.dataSheetId === dataSheet.id) {
      this.props.appActions.updateInDataSheet('sheet1', row);
    } else {
      this.props.appActions.addToDataSheet('sheet1', row);
    }
  }
  
  
  render() {
    
    const style_elIconButton2 = {
      display: 'block',
      textTransform: 'uppercase',
      backgroundImage: 'url('+btn_icon_456139+')',
      backgroundRepeat: 'no-repeat',
      backgroundSize: '88.887%',
      backgroundPosition: '50% 0%',
      color: '(null)',
      textAlign: 'left',
      backgroundColor: 'transparent',
      cursor: 'pointer',
      pointerEvents: 'auto',
     };
    
    const style_elIconButton = {
      display: 'block',
      textTransform: 'uppercase',
      backgroundImage: 'url('+btn_icon_20565+')',
      backgroundRepeat: 'no-repeat',
      backgroundSize: '90.122%',
      backgroundPosition: '50% 0%',
      color: '(null)',
      textAlign: 'left',
      backgroundColor: 'transparent',
      cursor: 'pointer',
      pointerEvents: 'auto',
     };
    
    const value_testName = this.state.testName;
    
    const style_elTestName = {
      display: 'block',
      backgroundColor: 'white',
      paddingLeft: '1rem',
      boxSizing: 'border-box', // ensures padding won't expand element's outer size
      textAlign: 'left',
      pointerEvents: 'auto',
     };
    
    const value_testuserEmail = this.state.testuserEmail;
    
    const style_elTestuserEmail = {
      display: 'block',
      backgroundColor: 'white',
      paddingLeft: '1rem',
      boxSizing: 'border-box', // ensures padding won't expand element's outer size
      textAlign: 'left',
      pointerEvents: 'auto',
     };
    
    return (
      <div className="TestList">
        <div className="foreground">
          <button className="actionFont elIconButton2" style={style_elIconButton2} onClick={this.onClick_elIconButton2}  />
          <button className="actionFont elIconButton" style={style_elIconButton} onClick={this.onClick_elIconButton}  />
          <input className="baseFont elTestName" style={style_elTestName} type="text" placeholder={this.props.locStrings.testlist_testname_746235} onChange={this.textInputChanged_elTestName} value={value_testName !== undefined ? value_testName : ''}  />
          <input className="baseFont elTestuserEmail" style={style_elTestuserEmail} type="text" placeholder={this.props.locStrings.testlist_testuseremail_543323} onChange={this.textInputChanged_elTestuserEmail} value={value_testuserEmail !== undefined ? value_testuserEmail : ''}  />
        </div>
      </div>
    )
  }
  
}

I could also share the project as it is just a simple screen with the necessary configuration to link to my testProject in Firestore. I would really appreciate the way to make this right as it is an important part of my project.

Thank you!

Hi, does the same issue occur if you have text labels instead of input fields in the list component?

I would have to double check but I believe it does not happen in that scenario.

I tested and it indeed is about the input fields. We’ll investigate this.

Releasing the fix might take some time because we have a huge update in the making which revamps the whole design canvas rendering in the background. Basically it means that Studio will be dramatically faster with large projects. This work background work for this release was started already a year a go so the update is really big. I’m hoping that we can get it out before holidays but you never know how things go.

1 Like

Thank you so much for your answer and looking into it. I am looking forward to seeing that new version in the making and that you are able to solve the refreshing issue.

Let me know if I can help in anything. Thanks.