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?
Related
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.
I'm currently working on a custom component with Vue3. I defined it like:
import { defineCustomElement } from 'vue';
import Panel from '~/components/panel_custom/Panel.ce.vue';
const CustomElement = defineCustomElement(Panel);
window.customElements.define('panel-custom', CustomElement);
Now I'm trying to access the shadowRoot to get some scroll-to-bottom function working.
How would I get access to the element to call the shadowRoot from Like: element.shadowRoot;?
I don't find anything in the vue documentation.
From within the Vue component, the shadow root is the parent node, so you could access it via this.$el.parentNode:
export default {
mounted() {
// assuming this Vue component is mounted as a custom element
// via `defineCustomElement()` and `window.customElements.define()`
console.log({ shadowRoot: this.$el.parentNode })
}
}
Or you can query the document for the custom element, and access the shadowRoot property directly from the reference. The following example assumes the custom element exists in the light DOM at the time of query, and not within the shadow DOM. document.querySelector() does not pierce the shadow DOM, so if the element is within another custom element with a closed-mode shadow root, the query will return undefined.
import { defineCustomElement } from 'vue'
import HelloWorld from '#/components/HelloWorld.vue'
const CustomElement = defineCustomElement(HelloWorld)
window.customElements.define('hello-world', CustomElement)
// assume element is in light DOM
const el = document.querySelector('hello-world')
console.log({ shadowRoot: el?.shadowRoot })
demo
I am trying to loop over an array of objects and display it in html using Angular 8.
My app.component.ts file is as shown below:
In the above code uptimeDataSet is the array of data that I need to loop over and display on another component.
My app.component.html file looks as shown below:
Finally, I am trying to loop over in my component to display the object in uptime-chart-component.html as below:
But I am not able to get the details in the UI. I am not able to find out where I am going wrong. Can someone please help me with this.
Update your uptime-chart.component.ts file-
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-uptime-chart',
templateUrl: './uptime-chart.component.html',
styleUrls: ['./uptime-chart.component.css']
})
export class UptimeChartComponent implements OnInit {
#Input() chartData: any[];
constructor() { }
ngOnInit(): void {
}
}
You need use #Input to capture the value in your child component. #Input decorator is used when you are passing data from parent to child. I suggest you take a look at this blog to understand- https://fireship.io/lessons/sharing-data-between-angular-components-four-methods/
And I believe, you can change your app.component.html without the *ngFor-
<app-user [chartData]="uptimeDataSet"></app-user>
if this is what you want your result to be
I have a custom Aurelia that can be invoked like
Test
This works fine using in a html page in the site.
However, I have some restful services that return html with these custom
elements. I then use this html as content in my Aurelia site. At this point the custom elements won't execute. This there a way to tell Aurelia to process the custom elements in the returned html before display ?
Thanks
You could use a combination of <compose> and InlineViewStrategy.
Gist demo: https://gist.run/?id=bd1122986ba8dabde8111c3b4ab6df6f
The main idea here is to have a custom component, which is able to use the html extracted from returned JSON result. With InlineViewStrategy, it's possible to get a full-featured template parser on-the-fly and to feed <compose> with it.
This way that chunk of html will be treated as any other part of the application. It can contain other custom elements as well.
Custom Element
Basically, it's just an extended <compose>, but for view bindable property it accepts a string variable instead of a view path.
part.html
<template>
<compose view.bind="viewStrategy" model.bind="model"></compose>
</template>
part.js
import {inject, bindable, InlineViewStrategy} from 'aurelia-framework';
import {Api} from './api'; // REST of your magic goes here
#inject(Api)
export class Part {
// template string
#bindable view;
// data model
#bindable model;
// rest api url (optional)
#bindable templateHref;
constructor(api) {
this.api = api;
}
// render html template
viewChanged() {
if (this.view) {
this.viewStrategy = new InlineViewStrategy(this.view);
}
}
// load html from remote url (optional feature)
templateHrefChanged() {
if (this.templateHref) {
this.api
.loadTemplate(this.templateHref)
.then(result => {
this.view = result.content;
});
}
}
}
Usage
remote api processing
// api call goes here
// JSON result could be similar to this
result = {
content:
`<template>
<require from="./custom-part"></require>
<h2>${model.title}</h2>
<custom-part title.bind="model.title"></custom-part>
<p>${model.content}</p>
</template>`,
error: false
};
this.testView = result.content;
app.html
Load template string from a variable
<part view.bind="testView" model.bind="testModel"></part>
Load template from an url
<part template-href="http://remote-api-url" model.bind="{title: 'Another...', content: '...'}"></part>
Load template from a non-existing url
<part template-href="./remote-api-notfound" model.bind="testModel"></part>
I hope it helps.
A few days ago I asked this question 2 way databinding in Aurelia custom elements - bind custom element to parent viewmodel
Now I need to be able to reuse the allSelectableValues from my custom element (my-custom.js) in my parent element (create.js).
I need this for a custom value converter I have on create.js which contains some Ids which I need to display names for instead, by looping through the array of elements, currently fetched and residing in my custom element.
**create.html**
<td>${d.SomeID | allSelectableValuesMapping}</td>
and
**value-converters/all-selectable-values-mapping.js**
export class AllSelectableValuesMappingValueConverter {
toView(value) {
for(let item in allSelectableValues) {
if (item.SomeID == value){
return item.Name;
}
}
}
}
In the ideal world I'd have hoped something like this would have worked:
**my-custom.js**
async attached() {
this.allSelectableValues= await await this.myService.getAllValues();
this.parent.allSelectableValues = this.allSelectableValues;
}
But my custom element have no idea of the parent which is requiring it.
Does anyone have an idea how to set the parent's allSelectableValues equal to the custom element's allSelectableValues from within the custom element? Or is there another, better way of achieving it, while still maintaining the two-way databound custom element?
Something like this ?
Please take extra note of the #customElement('CustomElement') declarator above the export class CustomElement line of code.
Custom Element View Model
import {inject} from 'aurelia-framework';
import {customElement} from 'aurelia-framework';
import {bindable} from 'aurelia-framework';
#customElement('CustomElement')
export class CustomElement {
#bindable arrItems
}
Custom Element HTML
<template>
<div repeat.for="item of arrItems">$(item.someProperty}</div>
</template>
Parent View Model
export class ParentViewModel {
parentArrItems = [];
}
Parent HTML
<template>
<require from="customelement"></require>
<CustomElement arrItems.bind="parentArrItems"></CustomElement>
</template>