Vue Showdown Default Classes - javascript

I want to achieve the following say i the MD as
md:'#H1'
I want to render it as
<h1>H1</h1>
I was able to achieve this using VueShowdown
but I want add default class to every h1 tag like
<h1 class="custom">H1</h1>
I got something similar to this here.
But I don't know how to use this in Vue.
Is it even possible in VueShowdown?
Is there any better library which has this functionality?

You can create a simple directive:
Vue.directive('default-classes', (parentElement) {
const els = parentElement.querySelectorAll('h1')
els.forEach((el) => {
el.classList.add('custom')
})
})
Then apply that directive to the VueShowdown component:
<VueShowdown v-default-classes :markdown="markdownBinding" />

Related

Angular: How to use a component dynamically in another component?

I have an DialogService for Angular Material:
constructor(private dialog: MatDialog){}
openDialog(dialogData){
const dialogRef = this.dialog.open(DialogComponent, {
data: dialogData
}
}
and a DialogComponent to open the dialog with:
let componentToRender
constructor(#Inject(MAT_DIALOG_DATA) public dialogData){
this.componentToRender = dialogdata.componentToRender
}
and this template for it:
<div class="dialog">
<ng-container></ng-container> // Here i want to dynamically render a given component
</div>
I want to give my dialogService with the dialogData a reference to an component that i want to be rendered inside my diaologComponent <ng-container>
The result should be, that i can call my service with a reference to a component to open a dialog container that renders this given component inside the component.html's ng-container. For example like so:
let dialogData = {}
dialogData.componentToRender = COMPONENT_TO_RENDER_INSIDE_OF_DIALOG
this.dialogService.openDialog(dialogData)
The idea is to make something like a dialog-container where the body can be any component i want to render inside of the dialog-container
I hope it is enough to write only the essential code, because I ask this question from another computer and could not copy paste the stuff I already have. thank you :)
For now I kind of solved this with ViewContainerRef.
I use the createComponent() method and give it the Component I want to render.
Then I insert the create ref inside my ng-template.
#ViewChild('container', {read: ViewContainerRef}) container!: ViewContainerRef
const componentRef = this.viewContainerRef.createComponent(MY_COMPONENT_DYNAMICALLY_GIVEN)
this.container.insert(componentRef.hostView)
This works but also renders my component selector tag around my content.
<my_inserted_component> <!-- I need to get rid of this :D -->
<!-- contents of my_inserted_component -->
</my_inserted_component>
That sadly results into Layouting problems. So now I need to find out how to change my CSS or (better) how to get rid of the outer tag with the component selector name.
EDIT: Also I should mention that I am on Angular 14

How do you create web components with customizable templates using Angular Elements?

I would like to create a library of web components using Angular Elements that have default templates but allow developers to override the output.
For example, consider a search-results component. I might have a default template that looks like this:
<h1>Search results for: {{query}}</h1>
But a developer might want to change the output to this (as an arbitrary example -- it needs to be flexible):
<h1>You searched for <strong>{{query}}</strong></h1>
My first thought was to simply use ng-content like this:
<search-results>
<h1>You searched for <strong>{{query}}</strong></h1>
</search-results>
However, this does not work and will literally output {{query}}.
I then discovered that I could add a TemplateRef input parameter on my component and pass in an ng-template element which would parse expressions. This works well within an Angular application, but I'm not sure how to do this outside of an Angular context using the compiled web components that Angular Elements generates.
Can anyone explain how to do this?
I see two solutions.
Solution 1: HTML template
Define a HTML template and pass its id to the Angular component. There you clone that node (see example in link) and add it to the DOM.
Placeholders ({{query}}) do not work "out of the box" in that template. You could replace them manually or just update the template and watch for changes in the Angular component. (Mutation Observer)
I'm working on this idea right now... I'll post an update here once my code is on GitHub so you can have a look at it.
Solution 2: JS templates
Another idea is to work with JS templates. (EJS for example)
You define a template string that you pass to the Angular component. There you render it with the given data object.
You can create a function that parse the .....{{variable}}... to ...value...
replaceText(content: string) {
const match = content.match(/(\{\{\w+\}\})/g)
match?.forEach(x => {
const variable = x.slice(2).slice(0, -2) || "fool"
const value = (this as any)[variable] || ""
content = content.replace(x, value)
})
return content
}
Then, you store the "ng-content" innerHTML in ngAfterviewInit. When you need, you call to this function.
Imagine some like -see that the "ng-content" is under a div "inner" with display:none
#Component({
template: `
<div class="alert alert-{{ type }} alert-dismissible" *ngIf="show">
<div [innerHTML]="newContent"></div>
<button type="button" class="close">
<span (click)="show = false; closed.emit()">×</span>
</button>
</div>
<div #inner class="hidden">
<ng-content></ng-content>
</div>
`,
styles:[`
.hidden{
display:none
}
`]
})
In ngAfterVieInit
#ViewChild('inner', { static: false }) inner!: ElementRef;
content:any;
ngAfterViewInit(): void {
this.content = this.inner.nativeElement.innerHTML;
}
And when you need
this.newContent = this.satinizer.bypassSecurityTrustHtml(
this.replaceText(this.content || '')
);
See a simple stackblitz
Use bypassSecurityTrustHtml method of DomSanitizer, provided by an angular; and bind it with html <div [innerHtml]="getSearchText()"></div>.
public getSearchText() {
return this.domSanitizer.bypassSecurityTrustHtml(`You searched for <b>${this.searchText}</b>`);
}
For more visit the angular documentation https://angular.io/api/platform-browser/DomSanitizer

how to add attribute without actually editing the HTML element in react

I have a below HTML component created in REACT which I cant edit directly. But I need to add one attribute to one of its HTML element. I can't use jquery as well other wise its easy to do with jQuery.
Below is the base HTML for table which I cant edit directly but I can just use this component in my code.
Challenge : I need to add attribute to the SVG element. e.g. -> data-id="1". Can it be done with CSS or any other way.
<TablePresenter>
<div>
<svg>this is a actually a sort button</svg>
<div>Column 1 Name</div>
</div>
<div>
<svg>this is a actually a sort button</svg>
<div>Column 2 Name</div>
</div>
</TablePresenter>
main file which I can edit is as below.
const MyComponent = () => {
some logic here...
Can we do something here may be CSS or any react hack to get underline component HTML change.
return(
<TablePresenter></TablePresenter>
)
}
export default MyComponent;
Not a recommended way of doing, but using a ref you can achieve this, a sample below:
Add a wrapper div to your parent component (your own component which can be edited) like below and add a ref to it, that will helps you to get the DOM reference of the html inside the <TablePresenter>
const divRef= useRef<HTMLDivElement>(null);
return <div ref={divRef}>
<TablePresenter></TablePresenter>
</div>
// This is an example of getting the reference of the svg.
divRef.current.firstElementChild.firstElementChild.firstElementChild
May be something like this:
const MyComponent = () => {
const divRef = useRef<HTMLDivElement>(null);
useEffect(()=>{
divRef.current.firstElementChild.firstElementChild.firstElementChild.attributes["data-id"]=1
}, [])
return <div ref={divRef}>
<TablePresenter></TablePresenter>
<SuperChild />
</div>
}

Dynamic Property Binding for Angular Directive Inputs

Hi I'm making a a drag directive but because of the way it works I can't get it to work on dynamic objects as it calls the id in the input.
#Input()
set Drag(options: any) {
this.stickerElement = document.getElementById(options.id);
}
Which works fine when the element isn't dynamic:
<div id="sticker" class="issues" [Drag]="{id: 'sticker'}">
but when it's set dynamically I can't figure out how to interpolate the ID dynamically.
<div [attr.id]="'Session' + Day.id" [Drag]="{id:'Session' + Day.id}"></div>
I've tried setting this.stickerElement with the #HostListener when you use it but that allows the directive to bubble and use child elements. I guess I can work around it but it doesn't feel right.
I feel like I'm missing some knowledge because no matter what I google nothing useful comes up about how to interpolate it correctly. Can you interpolate an attribute into a directive like this?
Thanks in Advance
B
I don't see any issue in the interpolation. However, document.getElementById(options.id) in Angular looks dirty. Instead you could use a template reference variable and directly send the HTMLElement.
Try the following
Template
<div appSticker #sticker [Drag]="{ref:sticker}"></div>
Directive
#Directive({ selector: "[appSticker]" })
export class StickerDirective {
stickerElement: HTMLElement;
#Input()
set Drag(options: any) {
this.stickerElement = options.ref;
}
constructor() {}
}
Also I don't see the directive binding in the <div> tag in your code.

is there anyway to access a css class in another html file which belongs to another component in Angularjs?

I have two components like this:
/top-navbar
top-navbar.component.js
top-navbar.module.js
top-navbar.template.html
and the other one is
/main-list
main-list.component.js
main-list.module.js
main-list.template.html
I have a function in:
top-navbar.component.js
which should take a css class in
main-list.template.html
and change it's value to what I need.
how should I do it?
I would appreciate it if you could help me.
You can try the following
const myElement = document.getElementsByClassName('my-element')[0];
document.getElementsByClassName will return HTMLCollenction, so with [0] you take a first element of it.
Then if you need to manipulate a class name
myElement.classList.add('MyClass');
myElement.classList.remove('MyClass');
if ( myElementclassList.contains('MyClass') )
myElement.classList.toggle('MyClass');

Categories