How to access composed children? - aurelia

I have a list of composed elements:
<compose repeat.for="foo of someList" view-model="./bar" model.bind="foo">
Now, from the parent, I would like to call a function on a specific bar view model. How do I do that?

You can add view-model.ref in your compose tag:
<compose repeat.for="foo of someList" view-model="./bar" model.bind="foo" view-model.ref="foo.barviewmodel">
You can replace view-model.ref by compose.ref. The both give the same result.
And in the parent you can call a function on a bar view model like this:
this.someList[2].barviewmodel.currentViewModel.action();
It works, but I don't know if it's a public api. See this issue for more details

Related

How to loop for each record in One2Many field in form view to create dynamic elements?

I have a customized One2Many field that contains several records for this current data.
I am working on a form view.
I need to construct something like this: (I don't want a tree)
<for every record in one2many_field>
<button something...>
</for>
I only want the result as to create 1 button per record in the one2many_field and be able to get the data in some fields from the model of the one2many_field too.
Is there any way to achieve it? I have searched for some time but found nothing even remotely close to this requirement.
You won't be able to achieve that in a Form View. Views in Odoo are kind of strict but it's mostly to avoid bad stuff to happen.
Anyway, you could think about re-creating the full view by yourself using QWeb View (doc for v14 here)
If you want to keep your Form View, you'll have to use a tree inside the form.
Know that you can totally add buttons in Tree views like adding on a sale.order.line something like <button class="btn btn-primary" type="object" name="product_id_change" string="Force Product Id Change"/> (useless, just for the example)
Check example image here
And play with some attrs to change the visibility of fields...
Hope it helped :)

Looking for child elements in a TagHelper

I am writing a custom TagHelper that should change its behavior based on what child elements its owner tag has. This will be used for substituting custom html elements in a localized string.
Here's a simple example of what I'm trying to do:
<h2 locale-key="Hello, %1!">
<span class="bold" locale-parameter="1">#userName</span>
</h2>
In the example above, the TagHelper for LocaleKey will change the content of the <h2> tag to a localized string. If this is a simple string with no parameters, then I can just simply use output.Content.SetHtmlContent() in the TagHelper to set the h2's content to the string. However in this case, the localized string has a parameter (%1), and I want the corresponding child element (<span parameter="1">) to be substituted in the final output. So the final rendered html would look like this:
<h2>Hello, <span class="bold">Lázár Zsolt</span>!<h2/>
To achieve this, I should be able to see all the child elements in the DOM from the LocaleKey TagHelper, so I can generate the correct HTML code. In the TagHelper's ProcessAsync method I can access the TagHelperContext and the TagHelperOutput, but I couldn't find any information about child elements in either of these objects while debugging. Is this possible somehow?
Another approach is to leave the string as is, with the %1 parameter key, and then use the child ParameterTagHelper to substitute itself into the parameterized string. To do this, I'd have to see the siblings of the current tag from the TagHelper.
Recursion would also be fun (e.g. the <span> is also localized and has its own parameters), but for the scope of this question, I'd be happy if I could get this to work without recursion.
I posted too soon again... There is a GetChildContentAsync() method in TagHelperOutput that will... get the child content asynchronously.

Aurelia How to get to function of composed child pages

I have a parent form that loads child forms into tabs.
The parent looks like this:
<div repeat.for="app of Apps">
<compose if.bind='app.Url.startsWith("modules/")' view-model="${app.Url}"></compose>
</div>
So each of the "compose" tags loads a different page based on URL.
How can I find the specific page and call a function from that page's ts file?
I have a temporary solution in place by, on the parent, declaring a variable with:
childPage: any;
and then on the activate event of the child, I do:
parent.childPage = this;
Then, on the parent page, I have can do:childPage.childFunction();
This of course doesn't give me intellisense and won't work with multiple children, but for now, it meets my needs.

asp-route-* not rendering query string inside view of view component

I have this anchor tag helper inside a view component:
<a asp-controller="Account" asp-action="Signup" asp-route-xxx="xxx" asp-route-returnUrl="/">Sign Up</a>
When it gets rendered in the browser, it looks like this:
It doesn't pass in the asp-route-* that I added. But the exact same tag helper I copy and pasted on a controller view, it gets rendered like this:
It contains the asp-route-* values in the query string. Do I need to do something to make it work for ViewComponents?

Conditionally Add Attribute

Is it possible to conditionally add an attribute to an element using binding syntax? I am aware of if.bind, but that targets elements. Rather I am interested in targeting a specific attribute on an element.
Example:
<a href.bind="model.link">${model.text}</a>
If model.link is falsy, then I don't want the href at all--just treat the <a /> as a container element.
I realize I could create two <a /> tags--one with the attribute and one without--and use an if.bind on both, but that seem clunky and un-aurelia like.
I don't think it's supported in Aurelia currently (issue 1, issue 2)
This,
<a href.bind="addLink ? link : ''">Link</a>.
will produce
<a href>Link</a>
if addLink is false.
It won't remove the attribute entirely. If you are using a library which will check the existence of an attribute to manipulate the element, then this won't work. Another option would be to create a custom attribute like this. But that seems like an overhead.