Skip to content

Blazor Html WebComponents make binding/setting Array/Object Properties easier #27654

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MichaelPeter opened this issue Nov 9, 2020 · 7 comments
Labels
affected-very-few This issue impacts very few customers area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. Needs: Design This issue requires design work before implementating. Needs: Spec Indicates that a spec defining user experience is required severity-minor This label is used by an internal tool Status: Resolved
Milestone

Comments

@MichaelPeter
Copy link

MichaelPeter commented Nov 9, 2020

Hello AspNetCore Team,

it is possible to define for Html Web Components complex objects or arrays as parameters.

Like if I want to pass a list of objects as table content or a list of links in a web component.

Here my sample component:

customElements.define('webcomp-property', class extends HTMLElement {
    constructor() {
        super();

        this._linkList = [{ href: "http://dummy.com", text: "dummy link" }];

        this._shadowRoot = this.attachShadow({ mode: 'open' });

        // https://developer.mozilla.org/de/docs/Web/Web_Components/Using_custom_elements
        this.render();
    }

    get linklist() {
        return this._linkList;
    }

    set linklist(value) {
        this._linkList = value;
        this.render();
    }

    //attributeChangedCallback(attrName, oldVal, newVal) {
    //    if (attrName === LinkListAttributeName)
    //        this.render();
    //}

    render() {
        var lnkListVal = this._linkList;

        this._shadowRoot.innerHTML = `
         <div>
          ${lnkListVal.map(lnk => `<a href="${lnk.href}">${lnk.text}</a>`)}
          <br />
         </div>
    `;
    }
});

Now currently if I want to set this property I need the following code:

Index.razor:

<webcomp-property @ref="_webcompSetProperty"></webcomp-property>

@code {
    private ElementReference _webcompSetProperty;

    List<Link> _links = new List<Link>()
        {
            new Link(href: "Counter", text: "Counter" ),
            new Link(href: "http://www.google.com", text: "Google" ),
            new Link(href: "http://www.bing.com", text: "Bing" ),
        };

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Links
        await JSRuntime.InvokeAsync<string>("setWebComponentProperty", _webcompSetProperty, "linklist", _links);
    }

Javascript:

function setWebComponentProperty(webComp, propertyName, value) {
    webComp[propertyName] = value;
}

How it could be done differently:

<webcomp-property @custom:linklist="_links"></webcomp-property>

@code {
List<Link> _links = new List<Link>()
        {
            new Link(href: "Counter", text: "Counter" ),
            new Link(href: "http://www.google.com", text: "Google" ),
            new Link(href: "http://www.bing.com", text: "Bing" ),
        };
}

Could this be improved?

I build a repository with differnet html web component issues, there are also other issues in there :
https://github.com/MichaelPeter/BlazorWebComponentTestApp

importaint are
https://github.com/MichaelPeter/BlazorWebComponentTestApp/blob/master/Pages/Index.razor
and
https://github.com/MichaelPeter/BlazorWebComponentTestApp/blob/master/wwwroot/scripts/TestWebComponents.js

Related:
#27070
#27651

@javiercn
Copy link
Member

@MichaelPeter thanks for contacting us.

So if I understood correctly you want a way to pass in objects/parameters from a Blazor component to a JS web component?

One quick thing that comes to my mind is that there is no straighforward way to deal with this. I'm not sure what the correct semantics here are, for example, should those objects be serialized or "passed by reference".

@javiercn javiercn added the enhancement This issue represents an ask for new feature or an enhancement to an existing one label Nov 11, 2020
@javiercn javiercn added this to the Next sprint planning milestone Nov 11, 2020
@ghost
Copy link

ghost commented Nov 11, 2020

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@MichaelPeter
Copy link
Author

MichaelPeter commented Nov 11, 2020

So if I understood correctly you want a way to pass in objects/parameters from a Blazor component to a JS web component?

Not just passing but also binding.

I think they should be passed as object, beeing passed as json should only be only done if defined explicitly.

But for example the lit element framework supports writing the property as json in html, as far as I know this is not web component standard. But don't Nail me down on that yet.

@javiercn javiercn added Needs: Design This issue requires design work before implementating. Needs: Spec Indicates that a spec defining user experience is required labels Nov 11, 2020
@SteveSandersonMS
Copy link
Member

I don't think that, in general, it's possible for something external to the web component to do 2-way binding to one of its JS properties, because there's no standard way to receive notification that one of its JS properties has changed.

If there is some standard mechanism I'm missing, please provide details. Thanks!

@SteveSandersonMS SteveSandersonMS added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Jan 26, 2021
@SteveSandersonMS SteveSandersonMS added affected-very-few This issue impacts very few customers severity-minor This label is used by an internal tool labels Jan 26, 2021 — with ASP.NET Core Issue Ranking
@ghost
Copy link

ghost commented Feb 1, 2021

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment. If it is closed, feel free to comment when you are able to provide the additional information and we will re-investigate.

See our Issue Management Policies for more information.

@MichaelPeter
Copy link
Author

MichaelPeter commented Feb 1, 2021

I don't think that, in general, it's possible for something external to the web component to do 2-way binding to one of its JS properties, because there's no standard way to receive notification that one of its JS properties has changed.

If there is some standard mechanism I'm missing, please provide details. Thanks!

Hello Mr. Sanderson,

thank you for your reply

hmmm, that is true there is no standard way to react on changes. Only Proprietary solutions (Notify on Polymer) and no onproperty changed. I am not that good in javascript but overriding attributeChangedCallback on bound attritbues and overriding defineProperty is not enough, since this not nessary indicate when a property is changed internally. Also it is quite an hack.

As minmal solution would it be possible for example to add to JSInterop or ElementReference (Extension-)Methods
like:

SetProperty()
GetProperty()
SetAttribute()
GetAttribute()

Think these would make building Blazor wrappers arround WebComponents much easier. Or is there something like that already?

Then I could write:

public int MyProperty 
{
    get => (int)_elRef.GetValue("MyProperty");
    set =>_elRef.SetValue("MyProperty"); 
}

And Custom event listener could notify about property changes.

Thank you for your time

Greetings Michael

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. Status: No Recent Activity labels Feb 1, 2021
@SteveSandersonMS
Copy link
Member

We do already have a backlog item for supporting getters/setters in JS interop: #25756

Seems like this issue is covered (as much as is possible) then, so I'll mark it as closed now.

@SteveSandersonMS SteveSandersonMS added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label Feb 2, 2021
@ghost ghost added the Status: Resolved label Feb 2, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Mar 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affected-very-few This issue impacts very few customers area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. Needs: Design This issue requires design work before implementating. Needs: Spec Indicates that a spec defining user experience is required severity-minor This label is used by an internal tool Status: Resolved
Projects
None yet
Development

No branches or pull requests

4 participants