Embedded view not showing when switching between views using ngIf - angular6

My component A has a child component B. On start up, A shows up because of conditition in *ngIf. A uses an EmbeddedView show show image thumbnails. A also has a button which when clicked changes the condition of *ngIf and shows B (because B shows on some other condition of *ngIf). If a button in B is pressed then A shows back again.
A's html is something like
<div *ngIf="this.tabType == this.questionTab" id="form-div-question" class="body__div--background">
....
<ng-template #thumbnailTemplate let-context="context">
<div id="{{context.divId}}">
<button id="{{context.buttonId}}" type="button" data-toggle="modal" (click)="showEnlargeImage(context)">
<img id="{{context.imgId}}" src="{{context.imgSrc}}"/>
</button>
<a *ngIf="this.isEditing" href="javascript:void(0)" id="{{context.closeId}}" (click)="deleteThumbnailFromContainer(context)"></a>
</div>
</ng-template>
...
<div id="image-thumbnail-container">
<ng-container #thumbnailContainer ></ng-container>
</div>
</div>
<div *ngIf="this.tabType == this.submittedAnswerTab" id="form-div-submitted-answer" class="body__div--background">
<b-component #bComponent [someInput]="..." (someEventFromB)="switchToQuestionTab($event)"></b-component>
</div>
The EmbeddedView in A is access as follows
#ViewChild("thumbnailContainer",{read:ViewContainerRef})
thumbnailContainerRef:ViewContainerRef;
What I am noticing is that on start up A shows fine including its embedded view. Then B also shows when the button in A is clicked. But when the view switches back to A then the embedded view doesn't show up!! (rest of A shows up correctly). I tried to force recreating the embedded view, I get error that the reference to the container is not defined (i.e.thumbnailContainerRef is undefined).
I also notice that when B is shown, it seem to be initiated everytime but when A is shown, it is not reinitialised everytime (maybe because B is child and A is parent)
Why is the container reference becoming undefined?

Taking inspiration from Angular 2 Show and Hide an element and What is the difference between *ngIf and [hidden]?
I seem to have solved the problem by using [hidden] instead of ngIf of A component.
<div [hidden]= "this.tabType != this.questionTab" ...>
</div>
<div *ngIf="this.tabType == this.submittedAnswerTab" id="form-div-submitted-answer" class="body__div--background">
<b-component #bComponent [someInput]="..." (someEventFromB)="switchToQuestionTab($event)"></b-component>
</div>
It seems that when '*ngIf' is false for A, Angular removes the embedded view and it doesn't get created again which seem to to be the reason why the ViewContainerRef is undefined when I switch back to A. Using [hidden] just hides A. Maybe there is code smell in my implementation but hey, I am still learning!

Related

Angular make div wait for google chart to load

I'm trying to get a page with various google charts to load in e pretty way (i.e display loading icon until chart is ready). Now some of the charts have a corresponding div that includes some text /info relating to the chart.
<ng-container *ngIf="stat1 && stat2; else loading">
<google-chart
[title]="title"
[type]="TYPE"
[data]="data"
[columns]="columnNames"
[options]="options"
[width]="width"
[height]="height">
</google-chart>
<div class="myDiv" *ngIf="stat1 && stat3">
my text
</div>
</ng-container>
<ng-template #loading>
<div class="loading">
my loading component
</div>
</ng-template>
This works as far as displaying a loading icon until the chart is ready however the content of the div appears before the chart causing the loading to look messy.
Any help as to how I can make the div only display after the chart is loaded would be awesome, as I can't seem to find a working answer online or in documentation. (I'm likely not searching for the correct terminology)
Thanks in advance.
Did you open their documentation ?
The ready event is emitted as soon as the chart got drawn and after every subsequent redraw.
<google-chart (ready)="onReady($event)"></google-chart>
Maybe use that ?

Angular - two the same ng-template with component in one HTML file (How to make reference, not copy)

I have the following problem: I create a web application using Angular. I am making a search form that has several fields. I have it ready as a component. Code below:
<ng-template #filter>
<app-articles-filter #articlesFilterDesktop
(onFilterFormSubmit)="submitFilterForm()"
[categories]="categories"></app-articles-filter>
</ng-template>
To put this code on the page, I'm using ng-container: <ng-container *ngTemplateOutlet = "filter"> </ng-container>. By default, the search form is at the top of the page. I also wanted to do so that when the user resize the window (mobile devices), a button will appear in the place of the search form. After clicking on this button a modal window with this search form would appear. Modal window code (I'm using Bootstrap):
<div class="modal fade" id="filterArticlesModal" tabindex="-1" role="dialog" aria-labelledby="filterArticlesModalTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<ng-container *ngTemplateOutlet="filter"></ng-container>
</div>
</div>
</div>
</div>
Having the same component twice with ng-template in one HTML file, I get a warning in the console:
"Found 2 elements with non-unique id [duplicated id here]: [html from search form here]".
The fields completed in the search form are not automatically completed in the modal view. (When I complete the form on the page, narrow the browser window and open the modal window.. there are empty fields in the modal window and vice versa). As I understand it, Angular just pastes the code and that's it. Is it possible to somehow treat this code fragment (my search form component) as one reference and not a copy?
EDIT:
I'm not sure about the duplicate ID fiasco. You could remove id's and just go off of classes, or maybe have some property from the component added in to the ID that you can control: id="searchBar{{foo}}"?
Solving the data consistency when you switch between searches can definitely be done.
If you want to have the search value act as a singleton I recommend putting that value in a service, and referencing it from the components. This can be done a few different ways, and there is one thing to consider:
Do you want the search to persist after the page in navigated to/from? If yes then keep the service that stores the search global, if not define it in the providers: [] property of the component that houses these search components (that way it gets deleted each time the component is destroyed)

Angular Accordion accessibility issues

have an issue with the expansion of the accordion containing a list of items using a keyboard.
There is a complication in that all the accordion's data is being populated from an API, so a lot of the solutions that I had seen are hardcoded. For example, using the information found in the article below didn't work as the unique values are hard coded:
https://www.hassellinclusion.com/blog/accessible-accordion-pattern/
I've added in a lot of the appropriate ARIA labels and navigating via tab around it works well as does the screen reader, but I can't get the accordion to expand.
I tried to talking it from another angle by getting the enter button to be interpreted as a click on the element to expand the accordion but got completely lost trying to do such a thing in Angular as inserting Vanilla JS is not as straight forward as it would seem.
Here is the code, it's spread over three components so I've compiled into one and removed some styling classes for legibility:
<div tabindex="0" (keydown.enter)="myFunction()" role="button">
<h2 tabindex="0">
<img>
<i tabindex="0"></i>{{ organiser.name }}
</h2>
//this component displays the selected item. the accessibility on this works fine
<app-selected-area role="region">
</app-selected-area>
</div>
<div class="content">
//this component displays the items that can be selected
<app-skill-item class="item">
<div tabindex="0" role="button">
<h3>{{ skill.name }}</h3>
<button *ngIf="updateable && isSelected()" (click)="select()">
Remove
<span class="screen-reader-only">
{{ skill.name }}
</span>
skill
</button>
<button *ngIf="updateable && !isSelected()" (click)="select()" tabindex="0">
Add
<span class="screen-reader-only">
{{ skill.name }}
</span>
skill
</button>
</app-skill-item>
</div>
Any help or hints would be much appreciated!
Ended up finding the answer for this in the follow question/thread:
Trigger click in Typescript - Property 'click' does not exist on type 'Element'
let element: HTMLElement = document.getElementsByClassName('btn')[0] as HTMLElement;
element.click();
this was the following code that let me manipulate the accordion via the enter key as a click

Using two ng-clicks, not working

I am working on a collapsible table.
I have a table with a ng-show. The header panel of the table uses an ng-click that toggles the ng-show piece to be true or false. However, I want to have a button at the top that toggles all the tables to one way or the other. It works unless I click on an individual table. If an individual table is clicked the toggle button ignores that table. Here's an example of what the code looks like.
<h3>{{page.name}}
<button type="button"ng-click="isOpen=!isOpen">Toggle</button>
</h3>
<div>
<div class="panel-heading" ng-click="isOpen=!isOpen">
<h3>{{table.name}}</h3>
</div>
<table ng-show="!isOpen">
~~table contents~~
</table>
</div>
The tables start out open, then close when either the toggle button is pressed or their headers are clicked. However the toggle button fails to change a table if it has been altered by clicking on the header.
One button would be the best, but having two buttons (one that opens them all, and one that closes them all) would work well too, and I feel might be the only way.
<button type="button"ng-click="isOpen=!isOpen">Toggle</button>
//lose a space.... and did you init the isOpen?
<button type="button" ng-click="isOpen=!isOpen">Toggle</button>

How to differentiate id or class without changing properties

I'm making a webpage that's using bootstrap-modal.js from Twitter bootstrap
bootstrap-modal.js allows you to create "modals." You basically click a button and a little javascript window slides down where you can display different content etc. Here's a demo http://jsfiddle.net/mjmitche/xt4aQ/44/
I'm going to have several buttons/modals on my webpage, so I have to set it up so each button triggers a different modal. I assume that the best way to do this is to give them different classes or ids
Problem, if I change the ids given by bootstrap-modal.js, it changes the properties of the modals...For example, it may remove or add a black screen backdrop etc. The fiddle linked to above shows how the code below works.
Question: Do you know how I could differentiate the modals so that each button triggers a different modal but allow them all to have the same properties?
<div id="modal-from-dom" class="modal hide fade">
<div class="modal-header">
×
<h3>Modal Heading</h3>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
Primary
Secondary
</div>
</div>
Button
<button data-controls-modal="modal-from-dom" data-backdrop="true" data-keyboard="true" class="btn important">Launch left Modal</button>
You said you can't use id's so why not classes? try adding a different class to each modal. Here is your updated fiddle: http://jsfiddle.net/xt4aQ/52/
And I tried changing the id to number "2" and it works just fine. Just copy all the code and change the id by appending an ascending number.