User can click the help icon to display a help message. It will close if the user clicks on the close icon in the message. This can be repeated an indefinite amount of time.
This works if both the help icon and the message with the close icon are inside the ng-controller.
However, if the help icon is outside and the message is inside it (see below), then I can display and close the help message, but it won't work if I try to display it a second time.
What am I missing?
<div ui-content-for="title">
<span>Page Title</span>
<span>
<i ng-click="isHelpVisible = true;" class="fa fa-question-circle">
</i>
</span>
</div>
<div ng-controller="InventoryController as inventory">
<div class="scrollable">
<div ng-show="isHelpVisible" class="alert alert-info alert-dismissible">
<a class="close" ng-click="isHelpVisible = false;"
aria-label="close" data-dismiss="alert">×</a>
Help message is here.
</div>
</div>
</div>
This is a data hiding problem caused by the fact that the ng-controller directive creates a child scope.
Instead of setting a scope property directly, set a property of an object on the parent scope.
<div ui-content-for="title">
<span>Page Title</span>
<span><i ng-click="help={isHelpVisible: true}" class="fa fa-question-circle"></i></span>
</div>
<div ng-controller="InventoryController as inventory">
<div class="scrollable">
<div ng-show="help.isHelpVisible" class="alert alert-info alert-dismissible">
<a class="close" ng-click="help.isHelpVisible=false;"
aria-label="close" data-dismiss="alert">×</a>
Help message is here.
</div>
</div>
</div>
Scope inheritance is normally straightfoward... until you need 2-way data binding.
If you try to bind to a primitive (e.g., number, string, boolean) in the parent scope from inside the child scope. It doesn't work the way most people expect it should work. The child scope gets its own property that hides/shadows the parent property of the same name.
Your workaround is to define objects in the parent for your model, then reference a property of that object in the child.
For more information, see
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
Related
How do I gain access to the respective sibling element of my button from the ngFor iteration on my collection?
Dom Element, I'm attempting to access this DOM element, so I can alter the sibling element div.popup class. As shown in the Codepen example linked at the bottom of the post.
I'm very new with angular, please advise.
<button
#popBtn
href="#"
id="info"
class="info popup-trigger"
title="info"
(click)="PopUp($event)"
>
Popup
</button>
Prior to the posting here, I read on the following articles but I couldn't understand completely or relate to it.
Pass a reference to DOM object with ng-click
how to get DOM element with ng-click
How to get the element html clicked in a ngFor to add a css class?
Overview of code
Component.html
<section class="ArticlesGrid">
<div *ngFor="let article of articles" class="windowsBox">
<article class="ui-titlebar">
<h4 class="ui-titletext">{{article.title}}</h4>
</article>
<div class="windowsScreen">
<button
#popBtn
href="#"
id="info"
class="info popup-trigger"
title="info"
(click)="PopUp($event)"
>
Popup
</button>
<div class="popup" role="alert">
<div class="popup-container">
Close
<p>{{article.content}}}</p>
</div>
</div>
</div>
<p class="windowsTech">
Technologies:
<span class="THtml"></span>
<span class="TCss"></span>
<span class="TJs"></span>
</p>
</div>
</section>
Component.ts
PopUp(event: Event) {
//console.log(this.viewBtn.nativeElement.nextElementSibling.classList.toggle("is-visible"));
console.log(event);
// this.viewBtn.nativeElement.
}
SandBox Mockup
https://stackblitz.com/edit/angular-collection-popup?file=src/app/app.component.html
Function to mirror
https://codepen.io/Gugiui/pen/vweXYR
Thanks for reading my question. I hope you can advise/guide me
add template reference variable on popup div -
<div class="popup" role="alert" #popupDiv>
pass it in button click function -
(click)="PopUp($event, popupDiv)"
change class in PopUp method using plain javascript -
PopUp(event: Event, element) {
element.classList.remove('popup');
element.classList.add('test');
console.log(element.classList);
}
I have the following v-for loop, in the scope of the first opening, and final closing <div> tags below.
The first :src is able to resolve the file name from the Vue.js variables.
The second :src (on line 12), is unable to resolve the variables into a string, and the browser instead searches for a file called: 'https://sample.com/' + orderInfo[product].FileName[index] which does not exist.
Why is the browser unable to interpret/resolve the variable names inside the modal, even though they appear to be in scope of the v-for loop.
<div v-for="index in orderInfo[product]" :key="index">
<img :src="'https://sample.com/' + orderInfo[product].FileName[index]"/>
<div class="file-detail">
<a data-open="modal"></a>
</div>
<div class="reveal large" id="exampleModal1hello" data-reveal>
<button class="close-button" data-close aria-label="Close modal" type="button">
<span aria-hidden="true">Close X</span>
</button>
<img :src="'https://sample.com/' + orderInfo[product].FileName[index]"/>
</div>
</div>
tl;dr: How would I implement an accessible popover? (I'm using bootstrap at the moment, but open to any ideas)
One of the biggest accessibility problems I face is the use of popovers when providing extra help information.
The way I understand it, popovers (and I guess more broadly, modals) are used for extra information when a tooltip cannot suffice. Popovers require the user to "open/click/activate" a help button for a new DOM element to be appended (or otherwise displayed), with the help information. While tooltips passively shows/speaks information whenever a user focuses the element. The tooltip widget itself is still being considered by WAI-ARIA
Say I have a text-input field with a label. I want to attach supplementary content to that input, in the form of a clickable/actionable button.
Initially I had the popover button in the label, before finding out the hard way that label's can't have block-level child elements.
I'm aware this probably isn't the best way of implementing an accessible popover. Here is my help button:
<div class="facs-ctl-help">
<a role="button" aria-label="Show help for Template Id 2,003" tabindex="0" data-toggle="popover" title="">
<span class="fa fa-info btn-floating waves-effect facs-help-icon"></span>
</a>
</div>
and here is my popover:
<div class="popover tooltip-help" role="tooltip">
<div class="arrow"></div>
<h3 tabindex="-1">
<i class="fa fa-info btn-floating waves-effect facs-help-icon"></i>Help
<span class="offscreen"> for Template Id 2,003</span>
<span class="offscreen"> popup</span>
</h3>
<div class="popover-body"></div>
<input type="button" class="btn pull-right tooltip-hide-btn" value="hide" aria-label="Hide help for Template Id 2,003">
<div style="width: 100%; clear:both;"></div>
</div>
What should I be using/doing? Would this be a good use case for live-regions? If so, any example code?
It doesn't necessarily have to be a live region. It feels more like a modal dialog, especially if you have interactive elements in it, such as the hide button.
There's a working example of an accessible modal dialog on https://github.com/gdkraus/accessible-modal-dialog
I'm pretty new to angular, and I'm trying to create a modal as a component (trying not to use ui-bootstrap or libraries) and I'm having trouble wrapping my head around it. My code:
App.component('modal', {
templateUrl: '../modal.html',
controller: ChocoListCtrl
});
I have a modal.html which I want to reference my controller which displays items inside a cart:
<h2>Your Cart</h2>
<div ng-if="!cart.length">
There are no items in your cart
</div>
<div class="col-lg" ng-repeat="item in cart | unique : 'type'">
<div class="col-md">
<span>Type: </span>
<strong>{{item.type}}</strong>
</div>
<div class="col-md">
<strong>${{item.price}}</strong>
</div>
<div class="col-md">
<span>Quantity: </span>
<strong>{{item.quantity}}</strong>
</div>
<div class="col-md">
<button ng-click="removeItem()">Remove</button>
</div>
</div>
However that's really the extent of my knowledge. I'm not sure how to make the modal popup work or even start it. Any guidance would be greatly appreciated!
It looks like you've defined your component well, all you have left to do is rig up the trigger:
<modal ng-if="showModal"></modal>
<button ng-click="showModal = !showModal">Show Modal</modal>
This may change based on the configuration of the parent element, but it's the same idea.
Then style the modal in such a way that it pops up in the desired location. position:fixed, etc.
You may want to consider dropping a backdrop behind the modal that has an ng-click attached to it to close the modal.
I have the following code:
<div ng-repeat="item in selectedCategory">
<div class="repertoire-composer">
<div data-toggle="collapse" data-target="#compositions{{$index}}"
class="repertoire-composer-title">
<span class="fa fa-chevron-right"></span>
{{item.composer}}
<span class="fa fa-plus"></span>
</div>
<div id="compositions{{$index}}" ng-repeat="composition in item.compositions" class="repertoire-compositions collapse">
<div class="repertoire-composition">
{{composition}}
<span class="fa fa-remove" title="Remove"></span>
</div>
</div>
</div>
</div>
So what I basically want is to have a tree of multiple .repertoire-composer divs, each of which with one or many child .repertoire-composition inside its .repertoire-compositions div. So in the second repeat, angular should create one or more .repertoire-composition divs. However, what it seems to do is create more divs of the one the directive is on. Hope I've been explicit enough, here's the unwanted result:
So basically, why is my .repertoire-compositions div getting duplicated?
EDIT:
I was misunderstanding ng-repeat. This is the intended behaviour of it: to repeat the element the directive is on. Thanks for the clarification.
.repertoire-compositions is not being duplicated it's being actually ng-repeated by this part of your template:
<div id="compositions{{$index}}" ng-repeat="composition in item.compositions" class="repertoire-compositions collapse">
I guess it's because of the second ng-repeat on item.compositions, can you provide a set of data ?
I'm not sure but you can try this in the inner repeater:
<div id="compositions{{$index}}" class="repertoire-compositions collapse">
<div class="repertoire-composition" ng-repeat="composition in item.compositions">
{{composition}}
<span class="fa fa-remove" title="Remove"></span>
</div>
</div>