AureliaJS - replacing looped elements with a template (passing values?) - javascript

I have found https://sean-hunter.io/2016/10/23/inter-component-communication-with-aurelia/ where it is explained how simple communication of values can be made between a parent and a child template.
Now, I'm trying to apply that to the contact manager tutorial:
http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/contact-manager-tutorial/1
... also on https://github.com/aurelia/app-contacts/tree/master/src - in particular to the looped contact items, but I cannot get it to work.
I have made gists as an example, which can run on gist.run (note, gist.run seems to only work in Chrome, not in Firefox 50 yet - but you can replace gist.run/?id= with gist.github.com/ and look at the code):
Copy of original contacts manager app (works) - https://gist.run/?id=c73b047c8184c052b4c61c69febb33d8
My changes in the app (do not work) - https://gist.run/?id=47c4f1c053adbdf46f6a33413dd12d3d
This is what I'm trying to do: in the original contacts app, there is this in src/contact-list.html which works fine:
<template>
<div class="contact-list">
<ul class="list-group">
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
<h4 class="list-group-item-heading">${contact.firstName} ${contact.lastName}</h4>
<p class="list-group-item-text">${contact.email}</p>
</a>
</li>
</ul>
</div>
</template>
Now, I'd like to replace the inner elements of the "looped" li - that is, the a with the h4 and the p - with a new template.
So, I made src/contact-list-item.html:
<template>
<a route-href="route: contacts; params.bind: {id:theContact.id}" click.delegate="$parent.$parent.select(theContact)">
<h4 class="list-group-item-heading">${theContact.firstName} ${theContact.lastName}</h4>
<p class="list-group-item-text">${theContact.email}</p>
</a>
</template>
... and src/contact-list-item.js:
import {bindable} from 'aurelia-framework';
export class ContactListItem {
#bindable theContact;
}
... and changed src/contact-list.html as:
<template>
<require from="./contact-list-item"></require>
<div class="contact-list">
<ul class="list-group">
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<contact-list-item theContact.bind="contact"></contact-list-item>
</li>
</ul>
</div>
</template>
Basically, I've made a property in the contact-list-item class called theContact, and I'd like to bind it to the contact which is the looper variable in the repeat.for="contact of contacts" -- unfortunately, this doesn't work, as the data is not propagated (and so the contact names are empty). Also, the clicks on contact fiels do not propagate to show the details, even if I've changed click.delegate="$parent.select(contact)" to click.delegate="$parent.$parent.select(theContact)" in the new template.
What do I have to do, in order to have the data propagate form the li repeate.for loop, down to the new replacement template - and to have the app react on clicks on the new template?

Quick answer:
In contact-list.html, change:
<contact-list-item theContact.bind="contact"></contact-list-item>
to:
<contact-list-item the-contact.bind="contact"></contact-list-item>
Explanation:
HTML is not case-sensitive, but the convention is to use only lower-case letters. To respect that, Aurelia converts all camelCase variables to dash-case parameters and element names when interfacing with your HTML code.
More Information:
Dwayne Charrington wrote a good blog about this topic here:
http://ilikekillnerds.com/2016/06/dont-get-skewered-kebab-case-aurelia/

Related

How do I render a standalone component on NUXT 2 which doesn't destroy on route change

Usually in vue 2, you render a component that doesn't close on route change, you include it directly in your app.vu file. How do I achieve this in nuxt 2.
I am trying to implement a chat module and don't want to include the component on every instance it is needed (That will mean new socket connection on every route)
Is there a workaround?
Put that in your default layout, it should be enough.
More info here: https://nuxtjs.org/docs/concepts/views/#default-layout
Something like this in /layouts/default.vue
<template>
<div>
<nav>
<ul>
<li>
<NuxtLink to="/">Home</NuxtLink>
</li>
<li>
<NuxtLink to="/parent">Parent</NuxtLink>
</li>
</ul>
</nav>
<main>
<img src="~/assets/logo.svg" />
<Nuxt />
</main>
</div>
</template>
And a simple page should do it
<template>
<div>
<h1>Hello Nuxters! 👋</h1>
</div>
</template>
No need to define a specific layout here since default is the one used by default.
Codesandbox example available here: https://nuxtjs.org/examples/routing/nested-pages
Otherwise, you could indeed have your content nested inside of a main parent wrapper.

getByRole for text under li > a on test-library

I would like to use getByRole to write the test and I have html like following. when I use linkitem or 'link' as role. I cannt find element
// err
TestingLibraryElementError: Unable to find an accessible element with the role "listitem" and name "Click Me"
Here are the accessible roles:
--------------------------------------------------
list:
Name "":
<ul
class="bar-dropdownList"
/>
--------------------------------------------------
listitem:
Name "":
<li
class="bar-container"
/>
Name "":
<li
class="bar-actionContainer"
/>
--------------------------------------------------
// test.tsx
const name = screen.getByRole('listitem', {name: 'Click Me'});
// from screen.debug()
<ul class="bar-dropdownList">
<li class="bar-container">
<div>
<a class="bar-button">
<span class="bar-label">Click Me</span>
</a>
</div>
<div>
<a class="bar-button">
<span class="bar-label">Address</span>
</a>
</div>
</li>
</ul>
The problem is that React Testing Library will not recognize an anchor as a role="link" if it doesn't have an href. You can test this using RTL's Testing Playground -- if you try to query by the link role you'll get a node returned, but if you remove the href it returns nothing. You'll also note that if you remove the href and then attempt to navigate through the document by tabbing on the keyboard, the anchor element is now skipped and never receives focus. This is most likely the reason why RTL makes this distinction: browser treat an anchor without an href differently from an accessibility perspective. RTL tends to be pretty good about the rules it uses to match by accessible roles, so if it were me I'd err on the side of assuming that an anchor without an href represents an accessibility antipattern, and reassess how this is being built.

Vue.js: Use aria-controls with conditional rendering in vue.js

I have two buttons which toggle some additional information on screen.
I added the buttons the aria-controls attribute und I render an id for the infobox.
Now I still get an error, when I validate the html, because I show this infobox only if a variable in the vuex store is true.
I render it with v-if.
So that means if the button was not clicked the element is not in the DOM and therefore the corresponding id is missing and I get an error.
I tried to use v-show because this would only hide it.
But this would still only render one infobox instead of 2.
Is the only way to get this right to make two infoboxes in the template and add the v-show to both? Or is there a nicer way to use aria-controls.
Thanks for any help
Best
m
Edit:
These are my buttons which have aria-controls.
<template>
<div>
<ul v-if="nav.items">
<li
v-for="(item, key) in nav.items"
#keyup.esc="closeInfoBox">
<button to="" aria-controls="item.name" aria-expanded="false">Designathon</button>
</li>
</ul>
</div>
</template>
And this is my infobox component:
<template>
<div class="Infobox" v-if="infoboxOpen" id="//should correspond to aria controls">
<span v-html="infoContent">Some content</span>
</div>
</template>
Which is only shown if infoboxOpen === true (from vuex store) and the content is replaced depending on which of the buttons is pressed.
(I left out some of this stuff, to make the code easier to understand and to focus on my question here).
This is where I could replace the v-if with the v-show but that would still render only one content. And I would like to have it as dynamic as possible, because users can add more infoboxes in the backend...
Hope this helps understanding my issue.
You're almost there, just make aria-controls a dynamic attribute using
:aria-controls="infoboxOpen ? item.name : ''":
<template>
<div>
<ul v-if="nav.items">
<li
v-for="(item, key) in nav.items"
#keyup.esc="closeInfoBox">
<button to="" :aria-controls="infoboxOpen ? item.name : ''" aria-expanded="false">Designathon</button>
</li>
</ul>
</div>
</template>

Meteor 0.8.0: While building the application: Unexpected closing template tag

I have this section in my template, the unexpected closing template tag is the {{/if}}.
{{#if selected}}
<div class="Answer--selected">
{{else}}
<div class="Answer">
{{/if}}
<i class="fa"></i> {{title}}
</div>
What is wrong with this code?
I had my question answered at Meteor Devshop. One of the breaking changes in Meteor 0.8.0 is the new templating system called Blaze, which renders your templates in a fundamentally new way. Instead of re-generating the whole HTML fragment every time the template renders itself, Blaze finds only the DOM nodes that need to be updated and performs the minimum possible changes. This means that you're not allowed to have unclosed HTML tags inside of block helpers anymore.
So the corrected code looks like:
{{#if selected}}
<div class="Answer--selected">
<i class="fa"></i> {{title}}
</div>
{{else}}
<div class="Answer">
<i class="fa"></i> {{title}}
</div>
{{/if}}
HTH
I believe this will work as well if you just want to alter the class name based on the condition.
<div class="{{#if selected}}Answer--selected{{else}}Answer{{/if}}">
<i class="fa"></i> {{title}}
</div>
As long as you don't bust apart tag begin/end with your helper you should be okay.
Steve
Meteor 0.8.0 has a completely rewritten template engine. Called Blaze.
Take a look at the docs http://docs.meteor.com and specifically the wiki page on using blaze. https://github.com/meteor/meteor/wiki/Using-Blaze

Share buttons for different templates in ember.js

I have multiple models each of which has its own template. I want to share a footer of buttons accross the different templates so when the same button is pressed different functions are executed according to the selected template. The HTML looks like this:
<script type="text/x-handlebars" id="application" >
<menu>
<nav>
<ul>
<li>{{#link-to 'model1'}}Model 1{{/link-to}}</li>
<li>{{#link-to 'model2'}}Model 2{{/link-to}}</li>
<li>{{#link-to 'model3'}}Model 3{{/link-to}}</li>
</ul>
</nav>
</menu>
<div class="content">
<section>
{{outlet}}
</section>
</div>
<footer>
<ul>
<li><button class="action-undo" {{action undo}}>Undo</button></li>
<li><button class="action-save" {{action save this}}>Save</button></li>
<li><button class="action-saveContinue" {{action saveAndContinue this}}>Save & Continue</button></li>
</ul>
</footer>
</script>
You probably want to use the {{partial}} helper. It will inline a template (with the same context) when it is called.
To use the partial helper just create a template with a leading underscore, like :_buttons. To include that template you can now use {{partial "buttons"}}.
See: http://emberjs.com/guides/templates/rendering-with-helpers/
You can keep the application template with the footer so all templates inserted in the outlet will have the footer.
To get the actions triggering to some corresponding template, just override the route of that template, for example in the model1 template, you can create a App.Model1Route implementing the actions:
App.Model1Route = Ember.Route.extend({
actions: {
undo: function() {
// perform undo
},
save: function() {
// perform save
},
saveAndContinue: function() {
// perform save and continue
}
}
});
And for model2 template just override the App.Model2Route and add the actions to be triggered in that template, and so on.
Give a look in that fiddle to see this working http://jsfiddle.net/marciojunior/d3xA6/
Be careful because if some route don't implement some triggered action, an error is raised. In that case you can extract your footer to a partial and just add where is used.
I hope it helps

Categories