Is there an elegant way to run some code after the template for a component is loaded in Aurelia? - aurelia

I am new to ES6 and Aurelia. I would like to execute some code after a template for a component loads. What I'm trying to do is get the page down editor working inside an Aurelia component. The imports seem to work for the most part (although Sanitizer doesn't seem to be imported), but I'm not sure how to run my initialization code after the template loads.
import 'Markdown.Converter'
import 'Markdown.Sanitizer'
import 'Markdown.Editor'
export class AddProject {
constructor(){
}
}
// initialization code
var converter1 = new Markdown.Converter();//Markdown.getSanitizingConverter(); // commented out doesn't work
var editor1 = new Markdown.Editor(converter1);
editor1.run();
I just want to run my initialization code for the template after it get's loaded into the dom. Any ideas?

Use attached
export class MyClass{
attached(){
alert('My template is attached');
}
}

Related

Vue.js 3 : Accessing a dynamically created component

I have a vue.js 3 application that needs to dynamically create components and access them.
The proper way to dynamically create them and injected them in the DOM seems to be th wrap them in an app using createApp, and this part works, when I call test() a new copy of the components appears at the bottom of the DOM.
Now I need to be able to get a reference to that component son I can call public (exposed) methods on it.
In my (actual) code below, what would allow me to get a reference to my component ?
import { createApp, h } from "vue";
import ConfirmModal from '#/views/components/ui/confirm-modal.vue';
function test()
{
let componentApp = createApp({
setup() {
return () => h(ConfirmModal, { title: "Fuck yeah!", type: "primary" });
}
});
const wrapper = document.createElement('div');
wrapper.setAttribute('id', 'confirm-modal-0');
componentApp.mount(wrapper);
document.body.appendChild(wrapper);
let _confirmModal: ConfirmModal = ???????????????????
_confirmModal.show();
}
EDIT : Here's my use-case: I have a helper function in a service which is used to confirm actions (like deletes) using a Modal dialog. This helper/service is pure TS, not a Vue component, but needs to instanciate the modal (which is a vue component), have it injected in the DOM and have its public methods callable (by my helper/service).
Right now, the only thing that works is to have a sungle copy of the modal component in my root layout and have to root layout foward the ref to my service, which can then use the component. But this isn't great because I need multiple instances of the dialog, and isn't good SOC to have to root layout handle a modal dialog.

Vue.js Create a helper class to call your methods globally

I have just started my first project with Vue.js, I have managed to do a lot of basic things and now I am trying to structure the project. I want to achieve the highest possible code reuse. One of the most frequent cases of my application is going to be showing messages of different types, confirmation, information, etc. For this reason, I want to create a mechanism that allows me to launch these messages globally, regardless of where I call them.
As far as I have been able to advance, I have opted for the following variant:
1- I have created a directory called classes in my src directory.
2- I have created a file called MessageBox.js inside classes directory with the following content:
import Vue from 'vue';
export default class MessageBox extends Vue {
confirm() {
return alert('Confirm');
}
information() {
return alert('Information');
}
}
I define it like this because I want to call these methods globally as follows:
MessageBox.confirm();
I am really new to Vue.js and I was wondering if there is any other way to achieve the results I am looking for in a more efficient way .... or .. maybe more elegant?
Thank you very much in advance..
There are at least 2 ways of going about this:
Event bus
Rely on Vue.js internals to create a simple EventBus. This is a design pattern used in Vue.js.
Create a file and add the following lines to it
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;
Create your component that takes care of displaying global dialogs. This is usually registered at the top of the tree, so it can cover the entire real estate.
Import the event bus import EventBus from 'event_bus' and then register for the new events
EventBus.$on('SHOW_CONFIRM', (data) => {
// business logic regarding confirm dialog
})
Now you can import it in any component that wants to fire an event like so
EventBus.$emit('SHOW_CONFIRM', confirmData);
Vuex
You can also use vuex to store global data regarding dialogs and add mutations to trigger the display of the dialogs.
Again, you should define a component that takes care of displaying and push it towards the top of the visual tree.
Note: in both cases you should handle cases in which multiple dialog need to be shown at the same time. Usually using a queue inside the displaying component works.
It's an antipattern in modern JavaScript to merge helper functions that don't rely on class instance into a class. Modules play the role of namespaces.
Helper functions can be defined as is:
messageBox.js
export function confirm() {
return alert('Confirm');
}
They can be imported and used in component methods. In case they need to be used in templates, they can be assigned to methods where needed one by one:
Some.vue
import { confirm } from './util/messageBox';
export default {
methods: { confirm }
}
Or all at once:
import * as messageBox from './util/messageBox';
export default {
methods: { ...messageBox }
}
Helpers can be also be made reusable as Vue mixins:
messageBox.js
...
export const confirmMixin = {
methods: { confirm };
}
export default {
methods: { confirm, information };
}
And used either per component:
Some.vue
import { confirmMixin } from './util/messageBox';
export default {
mixins: [confirmMixin]
}
Or globally (isn't recommended because this introduces same maintenance problems as the use of global variables):
import messageBoxMixin from './util/messageBox';
Vue.mixin(messageBoxMixin);

Unknown custom element on downloaded template using Vue

I'll try to be short but clear.
I downloaded a template of Vuejs for admin (from here), but I am having troubles modifying it. I created one new component but I can't use it because is not being recognized. The console error says:
Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I don't know why is this happening because I am importing the component as every other one. Look the script code in the father component.
import LTable from 'src/components/UIComponents/Tables/Table.vue'
import ETable from 'src/components/UIComponents/Tables/EditableTable.vue' //THIS IS MY NEW COMPONENT
import Card from 'src/components/UIComponents/Cards/Card.vue'
const tableColumns = [//some data]
const tableData = [//some data]
export default {
components: {
LTable,
ETable, //THIS IS MY NEW COMPONENT
Card
},
data () {
return {
//some data
}
},
//some methods
}
Of course the name tag in my new component is 'edit-table'.
There is happening other strange issue: when I change the name value in the component imported as 'LTable' it seems not to matter because everything keeps working good.
Please, any help is appreciated it.

Failed to access innerhtml elements in angular5

I am trying to access innerhtml elements in my component using it's id attribute.It works if I add the element directly into my template,but when I added the element through html binding I failed to access it in component.
html
<div [innerHtml]="testVal | safingHtml"></div>
component
testVal='<a id="up1">hello</a>';
ngAfterViewInit() {
const elem=document.querySelector('#up1');
console.log(elem);
}
In the above code I am trying to access the html elelment after completing the initialization process.The code works if I added the elelment directly into the template otherwise it returns null.
I am also using custom pipe having 'DomSanitizer' to get the html attributes(id,style).
custom pipe
import {DomSanitizer} from '#angular/platform-browser';
import {PipeTransform, Pipe} from "#angular/core";
#Pipe({ name: 'safingHtml'})
export class SafingHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(value) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
is there anyway to access the innerhtml elements by using it's id apart from using 'viewchild' property in angular5?

Using humane.js with aurelia

I'm trying to use humane.js with aurelia however I'm running in a problem.
It appears humane.js adds an element to the DOM when it's created and so far the only way I've found to do it is to force it like this....
showMessage(message) {
this.notify = humane.create();
this.notify.log(message);
}
However this creates a new instance of humane every time showMessage() is called. This breaks the queue as each one is rendered separately.
I've tried putting the create() in the activate() method of the view model but that doesn't seem to work either.
Any ideas?
This solved the problem, I've created a custom element for humane that is then included in app.html in the same way loading-indicator is in the skeleton app.
import humane from 'humane-js';
import 'humane-js/themes/original.css!';
import {inject, noView} from 'aurelia-framework';
import { EventAggregator } from 'aurelia-event-aggregator';
import { ApiStatus } from 'resources/messages';
#noView
#inject(EventAggregator)
export class StatusIndicator {
constructor(ea) {
this.ea = ea;
ea.subscribe(ApiStatus, msg => this.showMessage(msg.apistatus));
}
attached() {
this.humane = humane.create();
}
showMessage(message) {
this.humane.log(message);
}
}
The important part was the attached() this allows the setup of humane to work correctly.
Unfortunately for Aurelia, Humane will attach itself to the DOM automatically as a child of body, which Aurelia then replaces.
There is a really, really, simple fix for this:
Change your:
<body aurelia-app="main">
To this:
<body><div aurelia-app="main">
This way, Aurelia doesn't replace the div which is in body, you don't need to worry about attached() or where the import appears in your code, and humane works perfectly.
I have raised a humane github issue for this. https://github.com/wavded/humane-js/issues/69
Here is how I am using humane.js with Aurelia:
1) I load the CSS in the app index.html.
2) In each view model that requires humane, I import humane
import humane from 'humane-js/humane';
I do NOT inject human into the view model.
3) I show notifications like this:
humane.log('Error:, { addnCls: 'humane-libnotify-error' });
I hope this helps you.