Cant create dynamic textboxes using Renderer2 in angular4 - html

i'm working on Angular 4 and creating textboxes dynamically by clicking on a button using Renderer2. I had tried it on a dummy project first and it works well but when i put the code in my real project it won't work and there is no error on console and i had checked that the function is triggering or not by putting console.log in it and function is triggering and message is showing in the console but textbox creating code is not working. Can anyone help me in this?
Type script function
constructor(private renderer:Renderer2, private el: ElementRef ) { }
addfield() {
console.log('function triggered');
const div = this.renderer.createElement('div');
const input = this.renderer.createElement('input');
this.renderer.appendChild(div, input);
this.renderer.addClass(div, 'col-md-6');
this.renderer.addClass(div, 'col-sm-6');
this.renderer.addClass(div, 'col-xs-12');
console.log('cross passes the code');
this.renderer.addClass(input, 'form-control');
this.renderer.addClass(input, 'col-md-7');
this.renderer.addClass(input, 'col-xs-12');
}
Html code
<button class="btn btn-success" (click)="addfield()" >Add New Fiels +</button>

<div id="textboxes"></div>
<button class="btn btn-success" (click)="addfield()" >Add New Fiels +</button>
//
constructor(private renderer: Renderer2) {
}
addfield() {
....
const textboxes = document.querySelector('#textboxes'); //to get element
this.renderer.addClass(textboxes , "col-md-6"); //this is for add class
let divel= this.renderer.createElement('div'); //this is for create an element
this.renderer.appendChild(textboxes, divel); //this is for append a child element
}

Your code is absolutely fine, only issue is you are not appending dynamically created
elements to the ui
Component :
constructor(private renderer:Renderer2, private el: ElementRef ) {}
addfield() {
....
const textboxes = document.getElementById('textboxes');
this.renderer.appendChild(textboxes, div);
}
Template :
<div id="textboxes"></div>
<button class="btn btn-success" (click)="addfield()" >Add New Fiels +</button>
Here is the link to working demo :
https://stackblitz.com/edit/angular-dynamic-textbox

Try like this :
missing the following line to add dynamic textboxes this.renderer.appendChild(this.el.nativeElement, div);
addfield() {
const div = this.renderer.createElement('div');
const input = this.renderer.createElement('input');
this.renderer.appendChild(div, input);
this.renderer.addClass(div, 'col-md-6');
this.renderer.addClass(div, 'col-sm-6');
this.renderer.addClass(div, 'col-xs-12');
this.renderer.addClass(input, 'form-control');
this.renderer.addClass(input, 'col-md-7');
this.renderer.addClass(input, 'col-xs-12');
this.renderer.appendChild(this.el.nativeElement, div);
}

Related

How Can I insert string on the cursor position on the onClick event using ngx-codemirro text editor

Is there a way to insert a string at the current cursor position in ngx-codemirro?
I am new to ngx-codemirror and I have integrated ngx-codemirror in my angular project for the HTML code editor and it works fine, also I want to insert a string on the editor panel at the cursor position when I click the button. I'm trying some things but it is not working. please anyone who has experience ngx-codemirror help me.
ts:
export class CodeMirroComponent implements OnInit {
constructor() { }
content = '<p align="center">Hello</p>';
options = {
lineNumbers: true,
mode: 'markdown'
};
ngOnInit(): void {
}
insertString(content: any, str: any) {
var doc = content.getDoc();
var cursor = doc.getCursor();
var pos = {
line: cursor.line,
ch: cursor.ch
}
doc.replaceRange(str, pos);
}
}
HTML:
<div>
<ngx-codemirror
#codeMirror
[options]="options"
[(ngModel)]="content"
[autoFocus]="true"
>
</ngx-codemirror>
<button class="btn btn-sm btn-info"
(click)="insertString(content, 'this is new line')">
Name
</button>
</div>
As per the documentation.
https://sibiraj-s.github.io/ngx-editor/en/commands/
or use the transaction
for text or text-htmls
this.editor.commands.insertText(text).exec();
for other nodes like mention
const node = this.editor.view.state.schema.nodes.mention.create({
id: profile.id,
name: displayName(profile),
});
const state = this.editor.view.state;
const tr = state.tr.replaceWith(state.selection.from, state.selection.to, node);
this.editor.view.dispatch(tr);

How to close parent dialog from child in angular?

I have one parent dialog inside which there is one child dialog box resides.
In child dialog box there is a close button .
On click of this close button, I want to close both parent and child dialog box. How can we do it in angular6 ?
In my case works :
Parent:
const dialogRef = this.dialog.open(AssignResourcePageComponent);
dialogRef.componentInstance.modal_principal_parent.on('CLOSE_PARENT_MODAL',()=>{
dialogRef.close();
});
Child
#Output() public modal_principal_parent = new EventEmitter();
in the method close:
this.modal_principal_parent.emit('CLOSE_PARENT_MODAL');
You have to just pass the MatDialogRef of Parent dialog to the child dialog component in dialog data and close the same in child component code.
Please find below code
This is code of Parent Component dialog which opens Child dialog and sends parent MatDialogRef to child dialog component in Data :
#Component({
selector: 'confirmation-dialog',
templateUrl: 'confirmation-dialog.html',
})
export class ConfirmationDialog {
childDilogRef = null;
message: string = "Are you sure?"
confirmButtonText = "Yes"
cancelButtonText = "Cancel"
constructor(
public dialog: MatDialog,
#Inject(MAT_DIALOG_DATA) private data: any,
private parentDilogRef: MatDialogRef<ConfirmationDialog>) {
if(data){
this.message = data.message || this.message;
if (data.buttonText) {
this.confirmButtonText = data.buttonText.ok || this.confirmButtonText;
this.cancelButtonText = data.buttonText.cancel || this.cancelButtonText;
}
}
}
onConfirmClick(): void {
this.parentDilogRef.close(true);
}
// this method is used for opening child dialog
OpenChild(){
if (this.childDilogRef === null) {
this.childDilogRef = this.dialog.open(MyChildComponent, {
data: this.parentDilogRef, // parent dialog sent as data to child dialog component
});
this.childDilogRef.afterClosed().subscribe(result => {
this.childDilogRef = null;
});
}
}
}
This is code of child component which initializes provided ParentDialogRef to local dialogRef variable. and we close both the dialog ref on click of button on child dialog.
#Component({
selector: "child-dialog",
template: `<mat-dialog-content>
<p>
Click on button to close both dialogs
</p>
</mat-dialog-content>
<mat-dialog-actions align="center">
<button (click)="closeBoth()">close both dialogs</button>
</mat-dialog-actions>`,
})
export class MyChildComponent {
constructor(
public childDialogRef: MatDialogRef<MyChildComponent>,
public parentDialogRef : MatDialogRef<ConfirmationDialog>,
#Inject(MAT_DIALOG_DATA) public data: MatDialogRef<ConfirmationDialog>
) {
if(data){
this.parentDialogRef = data
}
}
// close the about dialog
onNoClick(): void {
this.childDialogRef.close();
}
closeBoth():void{
this.childDialogRef.close();
this.parentDialogRef.close();
}
}

Strange behaviour of event emitted by child component to parent component

I am emitting array of URLimages from child component to parent using EventEmitter.
Child's emitter:
#Output() images = new EventEmitter<string[]>();
Parent's html:
<app-file-upload (images)="onLoadedImages($event)"></app-file-upload>
where <app-file-upload> is the child.
Parent's OnLoadedImages() function:
onLoadedImages(images: string[]) {
console.log(images);
console.log(images[0]);
}
Console output:
Why does images[0] give undefined when in the console output I can see it has the data and how can I access images: string[] data?
Edit:
#Colby Hunter As an answer to comment, here's content of child:
#Component({
selector: 'app-file-upload',
templateUrl: './file-upload.component.html',
styleUrls: ['./file-upload.component.css']
})
export class FileUploadComponent implements OnInit {
loadedImagesAsURL = [];
#Output() images = new EventEmitter<string[]>();
constructor() {
}
ngOnInit() {
}
onFileSelected(event) {
const filesList = event.target.files;
for (const file of filesList) {
const reader = new FileReader();
reader.onload = (e: any) => {
this.loadedImagesAsURL.push(e.target.result);
};
reader.readAsDataURL(file);
}
this.images.emit(this.loadedImagesAsURL);
}
}
<div class="text-center" *ngIf="loadedImagesAsURL.length>0" style="height: 300px; overflow: auto;">
<span *ngFor="let image of loadedImagesAsURL">
<img style="width: 100%;" height="400" src="{{image}}">
</span>
</div>
<div>
<input type="file" multiple (change)="onFileSelected($event)" style="display: none;" #fileUpload>
<button type="button" class="btn btn-secondary" (click)="fileUpload.click()">Wybierz zdjęcia</button>
</div>
Browser's console does lazy evaluation. Try doing:
console.log(JSON.stringify(images));
console.log(images[0]);
you will see it as an empty array.
In your case by the time you manually click onto the console log of "images", the file gets loaded and you see the content.
Since you need to read all the files and do a final emission, make all the file read events as an observable,
emit your array once all the Obsevables are complete.
public onFileSelected(event): void {
let loadenedObs = this._createFileReaderObs(event);
forkJoin(...loadenedObs).subscribe(() => {
// all the files are read, emit the array now.
this.images.emit(this.loadedImagesAsURL);
})
}
private _createFileReaderObs(event): [] {
let obsArr = [];
const filesList = event.target.files;
for (const file of filesList) {
const reader = new FileReader();
const loadenedEventObs = fromEvent(reader, 'loadend').pipe(
tap(() => {
this.loadedImagesAsURL.push(reader.result);
}),
take(1) // take one event to complete the Observable
);
obsArr.push(loadenedEventObs); // create an array of loadened observables.
reader.readAsDataURL(file);
}
return obsArr;
}

ngIf not working

I'm using ngIf in a parent template. There I have the following code.
In html:
<button *ngIf="saveButton" type="button" class="button-success" (click)="save()">Save</button>
<add (setSavebutton)="setSavebutton($event)"></add>
In the component:
private setSavebutton(_boolean: any) {
this.saveButton = _boolean;
console.log(this.saveButton); // true
}
private save() { // save my item set by child }
In my child (add) I do:
#Output() setSavebutton: EventEmitter<any> = new EventEmitter<any>();
if (this.form.valid) {
console.log(this.form.valid); // true
this.setSavebutton.emit(true);
}
Both console.log return true but my button is not showing.
What am I doing wrong here?
EDIT
I found a work around.. They code of the child is the same.
In parent html:
<button [hidden]="!saveButton" type="button" class="button-success" (click)="save()">Save</button>
Why does the hidden work and the ngIf not?
It's not clear from your question where you code is called from.
A general workaround:
constructor(private cdRef:ChangeDetectorRef){}
private setSavebutton(_boolean: any) {
this.saveButton = _boolean;
this.cdRef.detectChanges();
console.log(this.saveButton); // true
}
With more information, it could be possible to suggest how to fix the root cause.

How to change button label on click?

When I click on this button,I want label to change. HTML:
<button pButton type="button" label="Edit" (click) = "foo()" style="width:auto"></button>
For example : before - "Edit", click, after - "Save".
You can simply bind it to your component variable inside your <button> tag.
<button pButton type="button" (click)="foo()"> style="width:auto">
{{myLabel}}
</button>
and in your component class:
#Component({
templateUrl:'./mytemplate'
})
export class MyComponent implements OnInit {
myLabel:string;
ngOnInit() {
this.myLabel = 'Edit';
}
foo() {
this.myLabel = 'Save';
}
}
Here is a working plunker: https://plnkr.co/edit/8TOn8oN63pgJ7eA7h7tY?p=preview
In your component class
#Component({
templateUrl:'./mytemplate'
})
export class MyComponent implements OnInit {
myLabel:string;
ngOnInit() {
this.myLabel = 'Edit';
}
foo() {
this.myLabel = 'Save';
}
}
In your html
<button pButton type="button" [attr.label]="myLabel" (click)="foo()" style="width:auto"></button>
Note that the html syntax has changed to start using property binding, where the "label" attribute of the node associated with the button element is being updated with the value of the myLabel variable in the component.
Read more about template and property bindings in this guide
https://angular.io/guide/template-syntax#property-binding
As a side note, if your requirement is to change the text displayed on the button, I would use interpolation as below
<button pButton type="button" (click)="foo()" style="width:auto">{{myLabel}}</button>
See this plunkr for a working example https://plnkr.co/edit/wEXKxP88kcsLKuBcUUxZ?p=preview
You can bind attributes via [attr.myAttribute] directive and as in your case you have to use [attr.label] to bind a value to the label attribute.
Inside your component you can define a label property which gets toggled on click:
class MyComponent {
private labelStates = ['Edit', 'Save'];
public label: string = this.labelStates[0];
public toggleLabel() {
let index = +(this.label === this.labelStates[0]);
this.label = this.labelStates[index];
}
}
And use it for your button:
<button [attr.label]="label" (click)="toggleLabel()"></button>
In case you want to change the button text use this:
<button (click)="toggleLabel()">{{ label }}</button>