Reputation: 4305
I am developing a custom attribute on aurelia to let user select from a list while typing in a textarea. For example, the usage will be something like this:
<textarea value.bind="description" placeholder="your description here" auto-complete></textarea>
and as you probably noticed, the auto-complete
is the attribute. Now when I want to show the hints, I want to do this in a custom-element to keep it simple. So the attached method of the attribute will be something like this:
attached() {
this.containerElement = document.createElement('div');
this.containerElement.style.position = 'relative';
const ce = document.createElement('autocomplete-menu');
this.containerElement.appendChild(ce);
const ceView = this.templatingEngine.enhance(ce);
ceView.attached();
const currentParrent = this.element.parentElement;
currentParrent.replaceChild(this.containerElement, this.element);
this.containerElement.appendChild(this.element);
}
now it opens and shows the hint area successfully. The screen-shot:
The problem gets started when I want to communicate to the generated element from the attribute view-model. For example, I want to send a data to its view-model or bind some object to a bindable property of that. For this issue I have found these solutions:
https://discourse.aurelia.io/t/dynamically-add-custom-attribute-to-element/1400/6 https://ilikekillnerds.com/2016/01/enhancing-at-will-using-aurelias-templating-engine-enhance-api/
and also read the last part of this:
https://aurelia.io/docs/binding/how-it-works#abstract-syntax-tree
and figured out that, I have to introduce an object for the element's view-model as its bindingContext or overrideContext. So if I am right, I have tested the solutions below:
this.containerElement.appendChild(ce);
let vm = { test: 1 }
const ceView = this.templatingEngine.enhance({ element: ce, bindingContext: vm });
ceView.addBinding(vm);
ceView.attached();
and
this.containerElement.appendChild(ce);
let vm = { test: 1 }
const ceView = this.templatingEngine.enhance(ce);
ceView.bind(vm);
ceView.attached();
console.log(ceView);
but on the attached lifecycle-hook of the element, I have logged the view-model and noticed that the bindingContext properties are not present on this
.
Now there are two questions:
bindable
s? I mean defining a bindable property on the element view-model and bind to it after the enhance method is done. Instead of working with bindingContext and overrideContext?Upvotes: 5
Views: 224
Reputation: 4305
Fortunately the problem has been solved. The solution was not that much complex but 1. it is very very useful for me (as I will describe next) 2. the lack of aurelia documentation made this simple issue hard to solve.
The problem was about I was misunderstanding the meanings of bindingContext and container. I was thinking that bindingContext will refer to view-model of the child element and I must point its container to the parent context (which is the attribute). But I found that I should point the bindingContext to the context of attribute. I still don't know enough about those two meanings but the solution is as simple and beautiful as the following sample:
this.containerElement = document.createElement('div');
this.containerElement.style.position = 'relative';
this.containerElement.style.display = 'flex';
this.containerElement.style.flexDirection = 'row-reverse';
this.ce = document.createElement('autocomplete-menu');
this.ce.setAttribute('filter.bind', 'filter');
this.ce.setAttribute('show.bind', 'showMentionPicker');
this.ce.setAttribute('parent-height', '${element.clientHeight}px');
this.ce.setAttribute('view-model.ref', 'mentionPickerViewModel');
this.ce.setAttribute('on-select.call', 'complete(mentionPickerViewModel.getRemainingOfHint())');
const ceView = this.templatingEngine.enhance({ element: this.ce, container: this.container });
ceView.bind(this);
ceView.attached();
this.containerElement.appendChild(this.ce);
const currentParrent = this.element.parentElement;
currentParrent.replaceChild(this.containerElement, this.element);
this.containerElement.appendChild(this.element);
and the bindings are referring to the attribute's this context which has the following properties:
filter = '';
showMentionPicker = false;
mentionPickerViewModel;
If the sample is not enough for your problem ask me for more information.
Upvotes: 2