How to manipulate DOM elements inside a TemplateRef without using pure javascript - angular6

I have this template in my Component class
<ng-template #thumbnailTemplate>
<div> <!-- top level div of thumbnail. This will have ids thumbnail-1, thumbnail-2 etc.-->
<img> <!-- this will have width, height=80-->
<a></a> <!-- the X button is created using CSS. This will have ids close-button-1, close-button-2. They'll also containn reference to the parent div id (thumbnail-1, thumbnail-2 ) -->
</div>
</ng-template>
<div class="form-group">
<div class="custom-file" id="file-upload" lang="es">
<input type="file" class="custom-file-input" id="question-file-upload" formControlName="image" [ngClass]="validateField('image')" (change)="handleFileSelect($event)" required>
<label class="custom-file-label" for="question-file-upload">
Select file...
</label>
</div>
<div id="image-thumbnail-container">
<ng-container #thumbnailContainer ></ng-container> <!-- This will contain the view created from #thumbnailTemplate. It can have multiple thumbnails. Check .ts file-->
</div>
</div>
</div>
When the use selects an image file from input element, I want to show a thumbnail of the image. I am able to do this using pure javascript code (createElement, setAttribute, addEventListener etc.) but I suppose I shouldn't mix JS code in Angular. So I plan to use ViewChild, Renderer2, ViewContainer and TemplateRef).
So far, I have got to the point where I have got reference of the template and the view container.
#ViewChild("thumbnailContainer",{read:ViewContainerRef}) thumbnailContainerRef:ViewContainerRef;
#ViewChild("thumbnailTemplate",{read:TemplateRef}) thumbnailTemplateRef:TemplateRef<null>;
#ViewChild("image-thumbnail-container",{read:ElementRef}) imageThumbnailContainer:ElementRef;
But I don't know how to get access to the div, img and a inside the template? As a user can select multiple files, the ViewContainer can have multiple Views of the TemplateRef. So I want to give the div and a different ids and also set the src of the img. I suppose I can useRenderer2APIs to set the attributes but for that I need to passnativeElementof thediv,imgandato it. But I don't know how to getnativeElement` of these as they are inside a template.

Related

Is there a way to drop in a stylesheet to get a Material theme or similar for all form elements on the page?

Is there a way to drop in a stylesheet that updates the form elements to material theme?
I'm using a plain HTML page and want the theme to fill in the width and heights of the form elements I have on the page.
I can assign class names to the elements to style them or if the stylesheet would apply to existing elements that would work as well.
You can assign the Material Design classes after you include the asset files in your project header and footer.
CDN:
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
NPM:
npm install #material/form-field
Button Example:
To style the button (submit for example), you add class as following, where foo-button will be your custom CSS to overwrite:
<button class="mdc-button foo-button">Button</button>
Form Example:
To style the form you can follow the Form Fields instruction.
<div class="mdc-form-field">
<div class="mdc-checkbox">
<input type="checkbox" id="my-checkbox" class="mdc-checkbox__native-control"/>
<div class="mdc-checkbox__background">
...
</div>
</div>
<label for="my-checkbox">This is my checkbox</label>
</div>
The JS part to handle error and validation is a little bit tricky, but if you use the console to manage the handlers etc, you should be able to manage.

Create component template to use it multiple times - Angular

This question might sound dumb, but I'll try it anyways:
Is it possible to use a component multiple times, but with different content? Something like a template.
To be exact, I want to write the component only once, but then use it in different places with different content - e.g. (I don't know whether that makes any sense and if so, how to realize it) by getting some text from an allocated model to fill a div, so that I can solely add a further model instead of editing the component itself?
Make use of the <ng-content>. Illustration:
app.component.html
<my-component>
<p>I'm getting projected into a component from outside because of ng-content</p>
</my-component>
my.component.html
<p>Data from my own component</p>
<ng-content></ng-content>
<p>Data from my own component</p>
By use of the <ng-content> you can project data from outside to within your component. You can make use of this in multiple ways, without changing the original component.
One way you can pass data to a component using input.
<my-component [text]="myText"></my-component>
And then in the component you can get the text using:
#Input() text: Person;
And display it in your template
You can use ng-content for this. Please find the below pseudo code
<!-- card.component.html -->
<div class="card">
<div class="card-header">
{{ header }}
</div>
<!-- add the select attribute to ng-content -->
<ng-content select="[card-body]"></ng-content>
<div class="card-footer">
{{ footer }}
</div>
</div>
<!-- app.component.html -->
<h1>APP COMPONENT</h1>
<card header="my header" footer="my footer">
<div class="card-block" card-body><!-- We add the card-body attribute here -->
<h4 class="card-title">You can put any content here</h4>
<p class="card-text">For example this line of text and</p>
This button
</div>
<card>

Angular: How can I remove wrapper (parent element) without removing the child?

I have seen this answer but it answers for jquery and not angular/typescript.
My question is similar to this question, but my question is seeking a solution for angular.
How can I remove wrapper (parent element) without removing the child in Angular using typescript or scss? (If it is possible by both kindly show both methods).
For example how to programatically manupulate the dom below from
<div class="wrapper">
<span>This is It!</span>
</div>
<div class="button">Remove wrapper</div>
to: (After clicking on the button I would like to have the dom iook like below)
<span>This is It!</span>
<div class="button">Remove wrapper</div>
EDIT:
Kindly also show how to set it so that it can add the wrapper div back when I click the button again. Basically toggling the wrapper div.
I think you can simulate using ng-template and two divs, some like
<div *ngIf="toogle" class="wrapper">
<ng-content *ngTemplateOutlet="template"></ng-content>
</div>
<ng-content *ngTemplateOutlet="!toogle?template:null"></ng-content>
<ng-template #template>
<hello name="{{ name }}"></hello>
</ng-template>
<button (click)="toogle=!toogle">toogle</button>
See a example in stackblitz

Angular 2 include component html in a component inherited template

I have a component A with its html/ts file. When I inherit a second component B from A, this will take all properties and method on the first. If I want to use the component A html, I can reference the comp A html in the templateUrl property.
I have a problem. I want use the component A html, but I want extend it. So my idea is "include" the first component html to the second. It's possible in Angular2? Is there another way?
I don't want to create an instance of component A in the component B. I want only the html markup.
EDIT:
In this example there is my problem:
https://stackblitz.com/edit/ng-content-projection-lzjwea
when I inherited the Hello2 ts, If I create an instance of hello component in hello2 html, it take its name property. I found three solutions:
Change all properties that need to be used in all inherit component to input and inject the
Duplicate html code
Find a way to reference the html of first component without creating an instance of it.
I think the best solution is the third. But I don't know a way to do it..
ng-content could be used to project dynamic content in a component.
For example, consider the following
hello.component.html
<div id='border'>
<h1>Base Component</h1>
<p>ng-content could be used for projecting dynamic content within a component</p>
<ng-content>
<!-- Dynamic content goes here -->
</ng-content>
</div>
So, now whatever that is in between
<hello>
<!-- dynamic html here -->
</hello>
app.component.html
<hello>
<div style="border: 2px solid red">
<h2>Child Component</h2>
<button id="sample1"> Sample 1 </button>
<button id="sample2"> Sample 2 </button>
</div>
</hello>
Example
Hope this helps

Wrap html element with Divs from custom directive

I have an <input /> tag which I want to wrap with some specific Div tags. I'm making custom directive in which I want to implement this functionality. But the problem which I'm facing is, element's prepend() method adds the whole tag i.e. it starts and ends before the targeted input tag. Similarly, append() method on element appends the Div inside the input tag, while what I actually want is,
On html:
<input id="oldinput" custom-textbox /> <!-- custom-textbox is my directive -->
After applying directive, in source, I want this:
<div id="mynewdiv> <!-- added from directive -->
<input id="oldinput" custom-textbox /> <!-- present input tag where I'd apply my directive -->
<div id="othernewdiv" /> <!-- new div to be added from directive -->
</div> <!-- end of newly added div from directive -->
But the result after using append() and prepend() functions:
<div id="mynewdiv> </div> <!-- added from directive, div ends here only -->
<input id="oldinput" custom-textbox > <!-- present input tag where I'd apply my directive, doesn't end here -->
<div id="othernewdiv" /> <!-- new div to be added from directive, it's added inside input tag -->
</div> <!-- end of newly added div from directive -->
</input> <!-- Wraps my newly added div -->
Completely strange behavior. Can someone help me with this?
wrap() does exactly what you want:
// wrap the input with a div
element.wrap('<div id="mynewdiv></div> ')
// add the second div
element.parent().append('<div id="othernewdiv" />')
You should take a look at ngTransclude and also the Developper Guide.
Creating a Directive that Wraps Other Elements
We've seen that you can pass in models to a directive using the
isolate scope, but sometimes it's desirable to be able to pass in an
entire template rather than a string or an object. Let's say that we
want to create a "dialog box" component. The dialog box should be able
to wrap any arbitrary content.