I’m working on a PR to the Poll plugin.
I’m attempting to render a Glimmer Component as a widget tree leaf as I’ve done several times before, but getting this strange error I’ve not seen before:
TypeError: this.parentMountWidgetComponent is undefined
firing on this line:
  
  
    
    
      
            setComponentTemplate(template, component); 
            this._componentInfo = { 
              element, 
              component, 
              @tracked data: this.data, 
              setWrapperElementAttrs: (attrs) => 
                this.updateElementAttrs(element, attrs), 
            }; 
            this.parentMountWidgetComponent.mountChildComponent(this._componentInfo); 
          } 
          updateElementAttrs(element, attrs) { 
            for (let [key, value] of Object.entries(attrs)) { 
              if (key === "class") { 
                value = [element[INITIAL_CLASSES], value].filter(Boolean).join(" "); 
              } 
              if ([null, undefined].includes(value)) { 
                element.removeAttribute(key); 
       
     
  
    
    
  
  
 
It seems that this.widget?._findView() || this._emberView
is undefined.
(this.widget exists)
  
  
    
    
      
                if ([null, undefined].includes(value)) { 
                  element.removeAttribute(key); 
                } else { 
                  element.setAttribute(key, value); 
                } 
              } 
            } 
            get parentMountWidgetComponent() { 
              return this.widget?._findView() || this._emberView; 
            } 
          } 
          RenderGlimmer.prototype.type = "Widget"; 
          /** 
           * Define a widget shim which renders a Glimmer template. Designed for incrementally migrating 
           * a widget-based UI to Glimmer. Widget attrs will be made available to your template at `@data`. 
           * For more details, see documentation for the RenderGlimmer class. 
           * @param name - the widget's name (which can then be used in `.attach` elsewhere) 
       
     
  
    
    
  
  
 
My very early stage code is here:
  
  
    
    
      
              } 
            }, 
          }); 
          createWidget("discourse-poll-option-dropdown", { 
            tagName: "div.irv-dropdown", 
            buildKey: (attrs) => `discourse-poll-option-dropdown-${attrs.option.id}`, 
            html(attrs) { 
              return [ 
                new RenderGlimmer( 
                  this, 
                  "div.irv-dropdown-content", 
                  hbsCli`<DropdownSelectBox @value={{@data.value}} @content={{data.content}} @onChange={{action (mut data.selectRank)}} @options={{hash showCaret=false filterable=false none="poll.options.irv.abstain" }} class="poll-option-dropdown"/>`, 
                  { 
                    ...attrs, 
                    value: 0 || "poll.options.irv.abstain", //option.value 
                    content: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], 
                    selectRank: this.selectRank.bind(this), 
                  } 
                ), 
       
     
  
    
    
  
  
 
Is it legal to use RenderGlimmer in this context?
             
            
              1 curtida 
            
            
           
          
            
            
              This relies on an ancestor having this property?
this._findAncestorWithProperty("_emberView")
which comes back undefined.
Or itself having an _emberView (which it doesn’t)
I’m guessing the ancestor should have had it set here:
  
  
    
    
      
          const t0 = Date.now(); 
          const args = this.args || this.buildArgs(); 
          const opts = { 
            model: this.model, 
            dirtyKeys: this.dirtyKeys, 
          }; 
          const newTree = new this._widgetClass(args, this.register, opts); 
          newTree._rerenderable = this; 
          newTree._emberView = this; 
          const patches = diff(this._tree || this._rootNode, newTree); 
          traverseCustomWidgets(this._tree, (w) => w.willRerenderWidget()); 
          this.beforePatch(); 
          this._rootNode = patch(this._rootNode, patches); 
          this.afterPatch(); 
          this._tree = newTree; 
           
     
  
    
    
  
  
 
OK a bit more info.
When the Poll is rendered (as a tree of widgets), this line is executed, but when you transitiion back to vote, it is not, thus for some reason there is no ancestor with an “_emberView” (Or it is not being found)
The source of this problem might be that the widget is never re-rendered:
 rerenderWidget() {
Is not fired again despite adding a new tree of widgets … so this property is never set.
… thus the solution to this might be scheduling a re-render when the Vote button is hit …
  toggleResults() {
    **this.scheduleRerender();**
    this.state.showResults = !this.state.showResults;
  },
… no this doesn’t solve it.
More info:
  _findAncestorWithProperty(property) {
    let widget = this;
    while (widget) {
      const value = widget[property];
      if (value) {
        return widget;
      }
      widget = widget.parentWidget;
    }
  }
This is searching up the tree for the property.
On the initial view this appears at the post-stream level.
But somehow the widgets appear to be losing their ancestry …
             
            
              
            
           
          
            
            
              OK so I’ve dug a little further:
  
  
    
    
      
              const refreshAction = dirtyOpts.onRefresh; 
              if (refreshAction) { 
                this.sendWidgetAction(refreshAction, dirtyOpts.refreshArg); 
              } 
            } 
            return this.draw(h, this.attrs, this.state); 
          } 
          _findAncestorWithProperty(property) { 
            let widget = this; 
            while (widget) { 
              const value = widget[property]; 
              if (value) { 
                return widget; 
              } 
              widget = widget.parentWidget; 
            } 
          } 
           
     
  
    
    
  
  
 
This is the hierarchy the widget traversal occurs up:
discourse-poll-option-dropdown-245da0f65a66dbd539bcd27e501d759a [widget.js:250:14](webpack://discourse/widgets/widget.js)
discourse-poll-option-245da0f65a66dbd539bcd27e501d759a [widget.js:250:14](webpack://discourse/widgets/widget.js)
poll-container-poll-1247 [widget.js:250:14](webpack://discourse/widgets/widget.js)
poll-poll-1247
Now the very last, existing widget … has no parent widget.
parentWidget is undefined.
And the kicker is that it has no “_emberView” property, so the result is undefined
So the property is never found and at that point the traversal stops.
             
            
              3 curtidas 
            
            
           
          
            
              
                david  
              
                  
                    Abril 17, 2024, 12:26pm
                   
                  4 
               
             
            
              The poll plugin is a little unusual in that the widget is mounted inside a post’s cooked HTML, rather than directly inside an Ember template via the <MountWidget component. So we probably need to add some extra logic here… will take a look 
Thanks for reporting @merefield !
             
            
              3 curtidas 
            
            
           
          
            
              
                david  
              
                  
                    Abril 18, 2024,  2:29pm
                   
                  6 
               
             
            
              I think if we merge this, it should make your code work @merefield 
  
  
    
    
  
      
    
      discourse:main ← discourse:widget-through-cooked
    
      
        
          opened 02:12PM - 18 Apr 24 UTC 
        
        
        
       
   
 
  
    In this case, the top-level widget being glued must have a `_postCookedWidget` a… ttribute. 
   
   
  
    
    
  
  
 
It’s not particularly pretty, but I think it’s ok since this is a pretty rare situation, and we hope to totally rip out all this widget/RenderGlimmer stuff in the not-too-distant future 
             
            
              4 curtidas 
            
            
           
          
            
            
              Thanks David.   Yes it makes sense that a compromise might suffice in the meantime 
I’ll test it once/if it is merged (and I’ll have to update my fork! 
             
            
              4 curtidas 
            
            
           
          
            
            
              Really appreciate the fast turnaround on this one, David.
I can confirm this is now working for me.
I’ll post here if I find any further issues with this arrangement.
(Screenshot Caveat: Very early days for this project!)
             
            
              2 curtidas 
            
            
           
          
            
              
                system  
              
                  
                    Maio 19, 2024, 11:15am
                   
                  10 
               
             
            
              This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.