Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    REACT create TabSet

    I’m trying to create a TabSet in React with dynamically created Tabs.
    Here’s my simple example:
    Code:
    <TabSet ID="templatesTabSet" width="100%" height="*" paneMargin="0">
      {isTabs &&
        <tabs>
          {this.templatesDS.cacheData.map((templates, index) => (
            <Tab
              title={templates[CONSTANT.TITLE]}
              key={index}
              templates={templates}
              pane={this.createTabPane(templates)}
            />
          ))}
        </tabs>
      }
    </TabSet>
    When I run it, I get an error.
    I found that without the <tabs> node, the TabSet renders without errors, so I tried this version:
    Code:
    <TabSet ID="templatesTabSet" width="100%" height="*" paneMargin="0">
      {(this.templatesDS.cacheData && this.templatesDS.cacheData.length > 0) &&
        <tabs>
          {this.templatesDS.cacheData.map((templates, index) => (
            <Tab
              title={templates[CONSTANT.TITLE]}
              key={index}
              templates={templates}
              pane={this.createTabPane(templates)}
            />
          ))}
        </tabs>
      }
    </TabSet>
    But I still get an error when creating the TabSet. What should I do?

    PS: The error occurs if this.templatesDS.cacheData = [].
    Last edited by Hirn; 3 Sep 2025, 06:20.

    #2
    Step #1 would be to tell us what the error is? Right it looks like it might be an error just in your React code, before creation of a TabSet is even attempted.

    Comment


      #3
      I get the following error
      Code:
      _5.add is not a function TypeError: _5.add is not a function at _3.isc_Canvas_addChild [as addChild]
      (http://localhost:3000/shared/isomorphic/system/modules/ISC_Core.js:3877:366) at _3.isc_TabSet_makeTabBar [as makeTabBar]
      (http://localhost:3000/shared/isomorphic/system/modules/ISC_Containers.js:342:160) at _3.isc_TabSet_initWidget [as initWidget]
      (http://localhost:3000/shared/isomorphic/system/modules/ISC_Containers.js:337:6) at _3.isc_Canvas_init [as init]
      (http://localhost:3000/shared/isomorphic/system/modules/ISC_Core.js:3598:6) at _3.isc_Class_completeCreation [as completeCreation]
      (http://localhost:3000/shared/isomorphic/system/modules/ISC_Core.js:401:6) at Object.isc_c_Class_create
      (http://localhost:3000/shared/isomorphic/system/modules/ISC_Core.js:261:47) at TabSet.__createSCInstance
      (http://localhost:3000/static/js/bundle.js:44764:27) at http://localhost:3000/static/js/bundle.js:45055:32 at Array.forEach (<anonymous>) at VLayout.getPropertyValue (http://localhost:3000/static/js/bundle.js:45002:25) at VLayout._getComponentConfigWithChildren
      (http://localhost:3000/static/js/bundle.js:44931:32) at VLayout.getComponentConfigWithChildren (http://localhost:3000/static/js/bundle.js:44894:17) at VLayout._createSCInstance (http://localhost:3000/static/js/bundle.js:44747:23) at VLayout.componentDidMount
      (http://localhost:3000/static/js/bundle.js:44690:10) at ki (http://localhost:3000/shared/js/react-dom.js:2:104072) at bi
      (http://localhost:3000/shared/js/react-dom.js:2:103857) at yi (http://localhost:3000/shared/js/react-dom.js:2:103401) at
      http://localhost:3000/shared/js/react-dom.js:2:115069 at ws (http://localhost:3000/shared/js/react-dom.js:2:115571) at ls
      (http://localhost:3000/shared/js/react-dom.js:2:108137) at S (http://localhost:3000/shared/js/react-dom.js:2:1399) at MessagePort.T
      (http://localhost:3000/shared/js/react-dom.js:2:1931)

      Comment


        #4
        The problem is that when this.templatesDS.cacheData is an empty array, the React code creates an empty <tabs> element which gets passed as an invalid structure to the SmartClient framework.

        The SmartClient React integration expects the tabs property to either be:
        1. Not present at all (undefined)
        2. An array of Tab configurations

        When you conditionally render <tabs>, but the array is empty, you're creating an empty container that doesn't translate to a valid tabs array.

        Solution: Don't render the <tabs> element at all when the array is empty:

        Code:
          <TabSet ID="templatesTabSet" width="100%" height="*" paneMargin="0">
            {this.templatesDS.cacheData && this.templatesDS.cacheData.length > 0 && (
              <tabs>
                {this.templatesDS.cacheData.map((templates, index) => (
                  <Tab
                    title={templates[CONSTANT.TITLE]}
                    key={index}
                    templates={templates}
                    pane={this.createTabPane(templates)}
                  />
                ))}
              </tabs>
            )}
          </TabSet>
        Or even simpler, just skip the <tabs> wrapper entirely when mapping:

        Code:
          <TabSet ID="templatesTabSet" width="100%" height="*" paneMargin="0">
            {this.templatesDS.cacheData && this.templatesDS.cacheData.length > 0 &&
              this.templatesDS.cacheData.map((templates, index) => (
                <Tab
                  title={templates[CONSTANT.TITLE]}
                  key={index}
                  templates={templates}
                  pane={this.createTabPane(templates)}
                />
              ))
            }
          </TabSet>
        The key is to ensure that when there are no tabs to render, you don't create any JSX structure at all - just let the conditional return false or null.

        In the meantime though, we'll make the code bulletproof here so even an empty <tabs> declaration works.

        Comment


          #5
          We've now bulletproofed the framework so that <tabs></tabs> no longer crashes. Will be available for tomorrow's builds, it would be great if you could confirm it works with your original code.

          Comment


            #6
            With this construction, when isTabs == false, I get an error in the browser console.
            Code:
                          {isTabs &&
                            <tabs>
                              {this.templatesDS.cacheData.map((templates, index) => (
                                <Tab
                                  title={templates[CONSTANT.TITLE]}
                                  key={index}
                                  templates={templates}
                                  pane={this.createTabPane(templates)}
                                />
                              ))}
                            </tabs>
                          }
            TypeError: _5.add is not a function
            at _3.isc_Canvas_addChild [as addChild] (ISC_Core.js:3877:366)
            at _3.isc_TabSet_makeTabBar [as makeTabBar] (ISC_Containers.js:342:160)
            at _3.isc_TabSet_initWidget [as initWidget] (ISC_Containers.js:337:6)
            at _3.isc_Canvas_init [as init] (ISC_Core.js:3598:6)
            at _3.isc_Class_completeCreation [as completeCreation] (ISC_Core.js:401:6)
            at Object.isc_c_Class_create (ISC_Core.js:261:47)

            Comment


              #7
              This looks like it's a problem with something outside of the code block you've shown. It might be that, with that shorthand conditional, you are basically providing the string "false" in the middle of your JSX, which is invalid.

              Comment


                #8
                Here’s an example of using conditions in JSX from your documentation, and I used it similarly.

                https://smartclient.com/smartclient-.....reactSupport
                Conditional JSX
                We support JSX that contains conditional child elements, such as:
                Code:
                 <DynamicForm ID="form1" width="621">
                     <fields>
                        <TextItem name="text" title="Text" hint="A plain text field" defaultValue="" wrapHintText="false" />
                        {showPicker && <ColorItem title="Color Picker" name="colorPicker" />}
                        <TextAreaItem name="textArea" title="TextArea" /> </fields> </DynamicForm>

                Comment


                  #9
                  I took the liberty of modifying your code in ReactComponent.js, and after that the version
                  Code:
                                <tabs>
                                  {this.templatesDS.cacheData.map((templates, index) => {
                                    return (
                                      <Tab
                                        title={templates[CONSTANT.TITLE]}
                                        key={index}
                                        templates={templates}
                                        pane={this.createTabPane(templates)}>
                                      </Tab>
                                    );
                                  })}
                                </tabs>
                  started working when this.templatesDS.cacheData = [].
                  Here are my changes:

                  Code:
                      _shouldInsertTypeDeclaration(typeName, child) {
                          let children = child.props.children;
                          if (!children) return;
                          let outerDesc = this._getClassPropertyDescriptor(typeName, child.type);
                          if (!outerDesc) return;
                          const isChildrenArray = isc.isAn.Array(children); // for me
                          if((isChildrenArray && !children.length) || !children.type) return; // for me
                          let propName = isChildrenArray ? children[0].type : children.type; // for me
                  Last edited by Hirn; 12 Sep 2025, 01:09.

                  Comment


                    #10
                    You've provided some context lines above your proposed patch, but none below. Just to confirm, your JSX code snippet works fine while retaining the original source lines below "let propName = ..." right?

                    Also, we ask that when a bug is reported, you include the SmartClient version that you're using. Can you please provide the result of isc.version (i.e. evaluated in the browser console)?

                    Comment

                    Working...
                    X