Using Aurelia's css bind you have to use this syntax
<div css.bind="{visibility: someField ? 'visible':'hidden'}">
is there a more succinct way to do this?
Please note, using show.bind is not what i'm after as this is equivalent to display:none and I actually want visibility:hidden (so the element takes up its space but is not visible)
Something like this would be ideal
<div visibility.bind="someField">
A little simpler syntax would be:
<div css=“visibility: ${someField ? 'visible':'hidden'}”>
To make this more succinct, you can easily create a custom attribute:
import {inject} from 'aurelia-framework';
#inject(Element)
export class VisibilityCustomAttribute {
constructor(element) {
this.element = element;
}
valueChanged(newValue) {
this.element.style.visibility = newValue ? 'visible' : 'hidden';
}
}
And use it like this:
<template>
<require from='./visibility-custom-attribute'></require>
<div visibility.bind="someField">
</template>
See this GistRun for an example.
Related
How do I reference an image in the Setup function in the Composition API? The path is '../assets/pic.png'
If I use the path directly inside the template, as the src in an img tag, the image displays on the page. When I inspect it, it shows the image name, followed by an id, then the file extension e.g: “/img/pic.123456.png”. I can do it like this to get what I want, but it doesn’t seem like the correct way of doing things in Vue.
I’m thinking it should be something like:
<template>
<div>
<img src="pic">
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup(){
const pic = ref('../assets/pic.png')
return { pic }
}
}
</script>
<style>
</style>
I believe it would work like this in the Options API (without ‘ref’, of course). I can’t get it to work with the Composition API. I'm thinking it may be something to do with the 'id'. Also how would I reference images in an array?
Thanks.
You need to require the image first with the require function, and then pass the returned value to ref. and you should bind the src attribute with v-bind.
here is a complete example based on your code:
<template>
<div>
<img v-bind:src="pic">
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup(){
const pic = ref(require('../assets/pic.png'))
return { pic }
}
}
</script>
<style>
</style>
I had the same issue, and using require didnt work for me, finally, I got this:
<template>
<div>
<img v-bind:src="pic">
</div>
</template>
<script>
import pic from '../assets/pic.png'
export default {
setup(){
}
}
</script>
I'm pretty new to vue.js and I'm trying to figure out how to use mixins.
I wondered if it is possible to create components which are bare of markup/template and contain only logic. As far as I understood, this should be possible and these components are called "mixins":
https://blog.bitsrc.io/understanding-mixins-in-vue-js-bdcf9e02a7c1
I'm using router functionality.
I'm now just trying out the vary basics of this concept and created the following:
listData1.vue, where the data for a list is created and then exported:
<script>
export default {
name: "listData1",
data() {
return {
list1: {
listData1A : "listData1A",
listData1A : "listData1B",
listData1A : "listData1C"
}
}
}
}
</script>
then listBuilder.vue, which takes the data and then uses it to create a list of items.
<template>
<div>
<ul>
<li v-for="element in list1" v-text="element"></li>
</ul>
</div>
</template>
<script>
import listData1 from "#/components/complexComponent2/listData1.vue"
export default{
name: 'listBuilder'
}
</script>
And then myComplexView2.vue in my views folder:
<template>
<div>
<h1>Second Awesome List!</h1>
<listBuilder />
</div>
</template>
<script>
import listBuilder from "#/views/myComplexView2.vue"
export default{
name: 'myComplexView2',
components: {
listBuilder
}
}
</script>
Now the result I get is this:
https://imgur.com/hQit785
But it should look like this:
http://localhost:8081/myComplexView
I'm a bit clueless what to do, especially since the vue dev tools in firefox don't show me much: https://imgur.com/RHJNy47.
Am I accessing the imported incorrectly?
Should I store the data differently, with the "data : {}" syntax or should I go for props in the listData component, like this:
props:["listData1"]
And then add the actual data in the component where the list is constructed with v-for? Though this would kind of undermine my goal to accomplish separating the data from the logic injecting it into the markup.
You need to setup listData1 as mixin in listBuilder.
<template>
<div>
<ul>
<li v-for="element in list1" v-text="element"></li>
</ul>
</div>
</template>
<script>
import listData1 from "#/components/complexComponent2/listData1.vue"
export default{
name: 'listBuilder',
mixins: [listData1],
}
</script>
Otherwise the ListBuilder won't have any data.
There's a typo in the mixin data:
listData1A : "listData1A",
listData1A : "listData1B",
listData1A : "listData1C"
Should be:
listData1A : "listData1A",
listData1B : "listData1B",
listData1C : "listData1C"
Apart from this, I don't see anything at syntax level in your code that would prevent mixin and v-for for working.
However, it puzzles me that myComplexView2 is importing myComplexView2.vue as the listBuilder:
import listBuilder from "#/views/myComplexView2.vue"
I don't know if this is an error you made when pasting to SO. Otherwise, the problem is probably here, since you need to import the listBuilder component, not the complex view.
I'm trying to build a custom element in Aurelia. At this point, this is what I have:
item.html
<template>
<span>${someProperty}</span>
</template>
item.ts
import {bindable} from 'aurelia-framework';
class Item {
#bindable someProperty: string;
}
parent.html
<template>
<require from="./item"></require>
<item repeat.for="item of items"></item>
</template>
parent.ts
class Parent {
items: Item[];
loadItems() {
// at this point, I'm sure that items is getting populated.
this.items = dataservice.loadItems();
}
}
I can't seem to find anything in the documentation that covers this scenario. What I'm getting, is that the span is empty. I'm not getting any errors in the console. Am I going about this the right way?
You need to bind to the item's someProperty. The following assumes that items[] is an array of strings.
<div repeat.for="item of items">
<item someProperty.bind="item"></item>
</div>
Sorry about the formatting, I'm on my phone.
You need to use the custom element and the bindable property. You also need to register the class as a custom element. Try this:
item.html
<template>
<span>${someProperty}</span>
</template>
item.js
import {bindable, customElement} from 'aurelia-framework';
#customElement('item')
class Item {
#bindable someProperty: string;
}
parent.html
<template>
<require from="./item"></require>
<item repeat.for="item of items" someProperty.bind="item"></item>
</template>
parent.ts
class Parent {
items: Item[] = [
'trees',
'swans',
'capes',
'a horse',
'triangles',
'witches',
'a different horse'
];
}
For more information, take a look at a few of my blogs on custom elements and custom attributes like this one: http://davismj.me/blog/semantic-custom-element/
Introduction
My goal is to create custom element in aurelia so that I can reuse it across the application.
In this context I've created component called operator-detail (operator-detail.html and operator-detail.js) which will holds information about operator and my plan is to reuse it in several places in application.
In this use case I have electornicRegistrationForm object which holds reference to operatorDetails and legalRepresentative. Both instances are injected into electornicRegistrationForm module and will be used as part of wizard allowing user to create a document which will be printed later on.
This electronicRegistraionForm is injected into operatorStep component.
operator-detail.html component I've included in operatorStep.html and confirm that component has been rendered correctly.
Problem
How to pass (bind) property operator from operatorStep.js to operator-detail.html component so that values from object operator are displayed (binded) in a two way binding manner.
In following example, value from this.operator.firstName 'First name from operator step' don't get displayed in operator-detail.html component.
Source code
electronicRegistrationForm.js:
import { OperatorDetail } from 'common/operator-detail';
import { LegalRepresentative } from 'common/legalRepresentative';
import { inject } from 'aurelia-framework';
#inject(OperatorDetail, LegalRepresentative)
export class ElectronicRegistrationForm {
constructor(operatorDetail, legalRepresentative) {
this.operator = operatorDetail;
this.legalRepresentative = legalRepresentative;
}
}
operator-detail.js
import {inject, NewInstance} from 'aurelia-framework';
import {ValidationRules, ValidationController} from 'aurelia-validation';
#inject(NewInstance.of(ValidationController))
export class OperatorDetail {
constructor(validationController) {
this.validationController = validationController;
this.firstName = '';
}
attached() {
ValidationRules
.ensure('firstName').displayName('Ime').required()
.on(this);
}
}
operator-detail.html
<template bindable="operatorvalue">
<div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="firstName" t='first_name'></label>
<input type="text" class="form-control" id="firstName" value.bind="operatorvalue.firstName ">
</div>
</div>
</div>
</template>
operatorStep.js
import { ElectronicRegistrationForm } from 'model/electronicRegistrationForm';
import { inject, NewInstance } from 'aurelia-framework';
import { RegistrationWizard } from 'registration/registrationWizard';
import { WizardStep } from 'registrationSteps/wizardStep';
import { ValidationController } from 'aurelia-validation';
import {bindable, bindingMode} from 'aurelia-framework';
#inject(ElectronicRegistrationForm, RegistrationWizard, NewInstance.of(ValidationController))
export class OperatorStep extends WizardStep {
#bindable({ defaultBindingMode: bindingMode.twoWay }) operator;
constructor(electronicRegistrationForm, regWiz, validationController) {
super(electronicRegistrationForm, regWiz, validationController);
this.operator = electronicRegistrationForm.operator;
this.operator.firstName='First name from operator step';
this.representative = electronicRegistrationForm.legalRepresentative;
}
}
operatorStep.html
<template>
<require from="common/operator-detail"></require>
<form validation-renderer="bootstrap-form">
<operator-detail operatorvalue.bind="operator"></operator-detail>
</form>
</template>
Declaring a bindable property on a template is for when you have a View without a ViewModel.
The bindable="operatorvalue" in your operator-detail.html doesn't work because you also have a ViewModel defined for this element. If you want to keep it this way then simply remove the bindable="operatorvalue" from the template and instead declare it in your ViewModel like so:
import {inject, NewInstance, bindable} from 'aurelia-framework';
import {ValidationRules, ValidationController} from 'aurelia-validation';
#inject(NewInstance.of(ValidationController))
export class OperatorDetail {
#bindable operatorvalue;
constructor(validationController) {
this.validationController = validationController;
this.firstName = '';
}
attached() {
ValidationRules
.ensure('firstName').displayName('Ime').required()
.on(this);
}
}
operator-detail.html would then become:
<template>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="firstName" t='first_name'></label>
<input type="text" class="form-control" id="firstName" value.bind="operatorvalue.firstName ">
</div>
</div>
</div>
</template>
Alternatively, you could make the bindable property declaration in the template work by simply deleting operator-detail.js and putting the validation stuff elsewhere. Then, rather than injecting OperatorDetail into the registration form you could new up the operator object like so:
import { LegalRepresentative } from 'common/legalRepresentative';
import { inject } from 'aurelia-framework';
#inject(LegalRepresentative)
export class ElectronicRegistrationForm {
constructor(legalRepresentative) {
this.operator = {};
this.legalRepresentative = legalRepresentative;
}
}
Both ways will work.
Working without ViewModels means putting the validation logic in electronicRegistrationForm.js for instance, which also means less code to write.
Working with ViewModels gives you more encapsulation, which is generally preferable if your view-specific logic is more complex than what you've shown here.
EDIT
In case you're using Google Chrome, I highly recommend using the aurelia context extension. You could then inspect the html and see that operator was defined in operator-step, but operatorvalue was undefined in operator-detail. This would tell you that the operatorvalue bindable declaration must be wrong, rather than something else.
How do I access & share variables between custom elements? I have the following files...
tip.html
<template>
<div class="tip-container">
<content select="tip-trigger"></content>
<content select="tip-content"></content>
</div>
</template>
tip.js
export class Tip {}
tip-trigger.html
<template>
<span class="tip-trigger" click.trigger="showTip()">
<content></content>
</span>
</template>
tip-trigger.js
export class TipTrigger {
showTip() {
console.debug(this);
}
}
tip-content.html
<template>
<span class="tip">
<content></content>
<span class="tip__close tip__close--default">×</span>
<span class="tip__color"></span>
</span>
</template>
tip-content.js
export class TipContent {}
In my Tip class I would like to have a variable name visible. When showTip is triggered visible would be set to true, which I would then use to add a class in tip-content.html. How can I share variables between these custom elements to do this?
The idea is to create an element to show tip pop-ups where any type of content can be the trigger and any type of content can be displayed when triggered. Basic example:
<tip>
<tip-trigger><button>?</button></tip-trigger>
<tip-content><div>Here is some helpful info...</div></tip-content>
</tip>
Here is a solution to your problem in Plunker.
Note that the tip-trigger and tip-content elements are just replaceable parts of the template. They don't needed to be components themselves (that confused me a lot in the "original" custom elements article).
app.html:
<template>
<require from="tip"></require>
<tip>
<tip-trigger><button>?</button></tip-trigger>
<tip-content><div>Here is some helpful info...</div></tip-content>
</tip>
</template>
tip.html:
<template>
<div class="tip-container">
<div>
<div click.trigger="showContent()">
<content select="tip-trigger"></content>
</div>
</div>
<div show.bind="contentVisible">
tip content:
<content select="tip-content"></content>
</div>
</div>
</template>
tip.js:
export class Tip {
showContent(){
this.contentVisible = !this.contentVisible;
}
}
Do you just need to turn Tip into a service-like class and import it?
export class Tip {
constructor() {
this.visible = false;
}
show() {
this.visible = true; // Or whatever to show the content
}
hide() {
this.visible = false;
}
}
Then:
import {inject} from 'aurelia-framework';
import {Tip} from './tip';
#inject(Tip)
export class TipTrigger {
constructor(tip) {
this.tip = tip;
}
showTip() {
this.tip.show();
// Or I suppose you could access 'visible' directly
// but I like the implementation details a method call offers.
}
}
*Disclaimer: This is untested.