Repeated content (sub-template) in AngularJS - html

I have a template which contains (in part) exactly the same content repeated two or three times with minor changes to the bindings, eg:
<div class="xyz-state0" data-ng-hide="data.error || !data.states[0].name">
<div class="xyz-content">
<img data-ng-src="{{data.states[0].image}}" width="48" height="48">
<span>{{data.states[0].name}}</span>
</div>
</div>
<div class="xyz-state1" data-ng-hide="data.error || !data.states[1].name">
<div class="xyz-content">
<img data-ng-src="{{data.states[1].image}}" width="48" height="48">
<span>{{data.states[1].name}}</span>
</div>
</div>
How do I write this to avoid duplicating this HTML? This is specific to its parent view (it won't be used anywhere else) so creating a full-blown widget seems wrong.
Basically I want something similar to ngRepeat, but I can't use that for the following reasons:
I need a specific (and different) style on each parent div.
I need to render a specific number of divs (2 in this case, 3 in another) regardless of whether or not they exist in the scope (ie. data.states could only have 1 element in it, but it still needs to create both divs).
In the other case the items need to be rendered out of order (first 1, then 0, then 2).
I've managed to get a template fragment in a separate HTML file and included it with ngInclude, but I don't know how to get a single name in its new scope to refer to a specific item. My first attempt was this, which doesn't work:
<div class="xyz-state0" data-ng-include="'state.tpl.html'" data-ng-init="state=data.state[0]"></div>
<div class="xyz-state1" data-ng-include="'state.tpl.html'" data-ng-init="state=data.state[1]"></div>
I suspect I could probably do it with a custom controller, but that seems like a heavy solution too. What's the Right Way™?

This is pretty much a textbook case for a custom directive. Define a directive, and then you can do
<state ng-repeat="item in data.states" item="item">.
Alternatively, if a custom directive is too much overkill (depends on whether you'll be reusing that view component elsewhere, mainly), you could just put an ng-repeat on the entire div. The only real issue is the class="xyz-stateN" stuff, but I bet you could hoke that up with ng-class usage.
EDIT:
if you do an ng-repeat, you can just use the $index key (as long as you're always counting up from zero and the state class is the same as the index). Something like
<div ng-class="{{'xyz-state'+$index}}" ng-repeat="state in data.states" data-ng-hide="data.error || !state.name">
<div class="xyz-content">
<img data-ng-src="{{state.image}}" width="48" height="48">
<span>{{state.name}}</span>
</div>
</div>
Would probably work fine. All that said, it's almost always worth making a directive in my opinion. Code gets recycled all the time, plus you can be cautious with namespacing and modularizing if that makes you nervous.

Well, this seems to do the trick (thanks to pfooti for the hint). I'm still not entirely happy with it as the directive is registered globally, whereas I really only want it in this one place.
state.tpl.html:
<div class="xyz-content" data-ng-show="state.name">
<img data-ng-src="{{state.image}}" width="48" height="48" />
<span>{{state.name}}</span>
</div>
view.tpl.html:
<div data-xyz-state="data.states[0]" class="xyz-state0"
data-ng-hide="data.error"></div>
<div data-xyz-state="data.states[1]" class="xyz-state1"
data-ng-hide="data.error"></div>
app.js:
app.directive('xyzState', [function() {
return {
templateUrl: 'state.tpl.html',
scope: {
state: '=xyzState',
},
};
}]);
Interestingly it doesn't work if I try to declare the introducing element as <xyz-state ...> instead of <div data-xyz-state="" ...>, despite the docs saying that this ought to work too. I assume there's some sort of validation thing interfering here.

Just as an FYI, I later revisited this code and decided to do it like this instead: (I'm letting my original answer stand as that is more like what I was originally asking for, and they both seem reasonable in different cases.)
view.tpl.html
<div data-ng-repeat="state in data.states" data-ng-if="!data.error"
data-ng-class="state.class">
<div class="xyz-content" data-ng-show="state.name">
<img data-ng-src="{{state.image}}" width="48" height="48" />
<span>{{state.name}}</span>
</div>
</div>
app.js
...
while ($scope.data.states.length < 2)
$scope.data.states.push({});
$scope.data.states[0].class = 'xyz-state1';
$scope.data.states[1].class = 'xyz-state2';
...
I've done something similar for the other (3-item) case, except there as I wanted to rearrange the order of the items I added an order property for the desired order in the controller and then used data-ng-repeat="button in data.buttons|orderBy:'order'" in the view.
This does mean that a bit of view definitions (display order and CSS classes) have leaked into the controller, but I think the benefit to code clarity outweighs that.

Related

How to show/hide nested divs using *only* CSS

I want to show/hide a specific div on-click, but there are some serious caveats. I should also mention I fundamentally know how to do this, using answers gleaned from similar questions here (eg., http://jsfiddle.net/6W7XD/1/), but this is more for the specific situation.
I have a CMS which will not allow me to edit the HTML at all outside of specific modules. Additionally, the CMS is one of those which disables id selectors, so I cannot use those, either.
I understand that the JSFiddle example I provided hinges on specific sibling/child selectors, but I'm wondering if there's a selector which would work for this situation. I can only edit the html in the first module (for simplicity's sake, I'll call it .module-1), but I want to show/hide .module-4
The arrangement of the code in the CMS, however, is a little bit byzantine.
This is a parred down version of what I'm working with (this is for a sidebar, by the way, housed under the beta id). I cannot edit any of the fundamental structure, except in the place marked:
<div id="beta-inner" class="pkg">
<div class="module-1 module">
<div class="module-inner">
<div class="module-content">
<!-- I can edit this area only, so this is where I would place my show/hide link. If the jsfiddle method I posted is appropriate in this situation, I'm assuming it would show/hide after clicking on links placed here. -->
<span class="span3" tabindex="0">Hide Module-4</span>
<span class="span2" tabindex="0">Show Module-4</span>
</div>
</div>
</div>
<div class="module-4 module">
<!-- this is the module I want to show/hide -->
<div class="module-inner">
<div class="module-content">
</div>
</div>
</div>
</div>
</div>
I can edit the CSS as much as I want, provided I don't use id (which has been made inaccessible to prevent people messing up the CMS? I think that's the rationale offered), and I believe that precludes the checkbox hack entirely.
I cannot use JQuery/JS/anything of that nature, since they're disabled. I know this would be a quick thing with jquery, but unfortunately, there's nothing I can do about that.
So... if this is possible... how would I go about doing it?

JSoup: Accessing Data Within Multiple HTML classes

I recently started using JSoup to do HTML data scraping and I couldn't find enough detailed information on jsoup.org on how to find div classes that are nested within other div classes.
<div class="Food">
<a href="/eating/101" class="Eating">
<div class="Groceries">
<div class="Vegtables">
<div class="LeafyGreens"
<img src="https://RealisticBroccoli.svg" alt="" class="Broccoli-logo"></div>
<div class="Broccoli Fact">Fun Fact About Broccoli:</div>
</div></a></div>
<div class="Food">
<a href="/eating/102" class="Eating">
<div class="Groceries">
<div class="Vegtables">
<div class="LeafyGreens"
<img src="https://CartoonBroccoli.svg" alt="" class="Broccoli-logo"></div>
<div class="Broccoli Fact">Fun Fact About Broccoli:</div>
</div></a></div>
I created a simplistic version of a similar HTML project I am working on. I know it seems like there is an excessive amount of div tags, but its what is making this problem challenging for me. I wanted to scrape the HTML text for the Broccoli Fact that is produced when the A[href] is eating/101 without scraping the fact from eating/102.
From my experience I cannot scrape the "Broccoli Fact" class using one instruction, it doesn't produce any output either. I think that it has something to do with the a href "/eating/101". Thanks for the help!
From what I understand you may have one or both of these 2 problems:
1) In HTML it is possible to assign more than one class name to an element. This is what happens here with Broccoli Fact. These are actually two classes: Broccoli and Fact. In your CSS selector in Jsoup you may want to apply both classes as well. This can be achieved by simply concatenating the classes. Note that a class selector in JSopu CSS does contain the class-name with a preceding dot: .Broccoli and .Fact So concatenation gives you
div.Broccoli.Fact
2) In the HTML you give as an example there are more than 1 Broccoli Fact, but you only want to get the first one. There are several ways of dealing with this. Which one is the best is hard to tell without more context knowledge of your task. However, here are some suggestions:
a) gather all Fun Facts of Broccoli but only use the first one. Since Jsoup returns Elements, which implements the List interface, you can quite easily access the first element.
b) Use a more precise CSS selector. Something like this could work:
div.Food>a[href$=101] div.Broccoli.Fact
Have a look here to learn about JSoup CSS selectors: https://jsoup.org/cookbook/extracting-data/selector-syntax

How to label a loading animation for WAI-ARIA?

I'm working on fixing some accessibility issues on a web page. I have this div that acts as a dialog, and inside at one point a div containing a loading animation and a text "Working..." is displayed.
I am unsure as to how to label these two items in order to correctly notify the blind user that there is a progress animation and that it's working and he should wait.
<div id="loading" style="display: none;">
<div class="mgBot15"><span class="txt16" role="alert">Working...</span></div>
<img src="loading.png" role="progressbar" aria-busy="true"/>
</div>
I tried adding the role and aria-busy properties to the img (also to the parent div, at first).
When this div appears (by changing the display style property), it correctly reads "Working..." but I hear no indication that it's busy and that the user should wait, am I missing something?
I've looked all over for examples for loading animations, to no avail so far.
Note: I'm using NVDA as a screenreader to test.
Thanks
The best solution I could come up with was using role alert, and aria-busy="true".
<div id="loading" style="display: none;">
<div class="mgBot15"><span class="txt16" role="alert" aria-busy="true">Working...</span></div>
<img src="loading.png" alt="loading" />
</div>
I believe the most sensible approach would to use the combo
aria-busy="true" aria-live="polite"
The reason for that is because some pages might have a lot of separate loaders (let's say one for each component, not a single loader for the whole page) and it you use aria-live="assertive" or role="alert" it will be very intrusive and each of the loaders will get called out.
The correct role to use here is progressbar as the original question used. Other roles like alert may work, but they are less specific, meaning assistive technology may present the information in a less ideal manner.
There are a few issue with the original question's example, though:
If you wish to have the text be announced in the same as an alert is, aria-live="assertive" should be used rather than the alert role. That aria-live value is what causes the screenreader to announce the text when it does for an alert.
The text to be announced should be set on the element with the progressbar role using the aria-valuetext attribute. It should not be set solely on a separate adjacent element. If it needs to also be included in another element for presentational reasons, that element should have aria-hidden="true".
Per the spec, aria-valuemin and aria-valuemax are to be specified even when the progress is indeterminate (like a spinning loading indicator). These could be set to 0 and 100 respectively as simple placeholders implying a percentage.
When the loading is complete, the aria-valuenow could be set to whatever was used for aria-valuemax, and aria-busy can be set to false.
This leads to one potential alternative to the original question:
<div id="loading" role="progressbar" aria-valuetext="Working…" aria-busy="true"
aria-live="assertive" aria-valuemin="0" aria-valuemax="100">
<div class="mgBot15" aria-hidden="true"><span class="txt16">Working...</span></div>
<img src="loading.png" alt="" />
</div>
After a day of fiddling with a similar issue, I was able to finally get this working with a lot of reading and experimenting. I'm using NVDA for a screen reader.
<div class="loader" show.bind="isLoading" role="alert" aria-label="Loading"></div>
The following attributes were key: role and aria-label.
Above example makes NVDA announce "Loading alert" once isLoading becomes true. Important to note is that NVDA pronounces the aria-label value, followed by "alert". Using roles "log" or "status" did not end up in any announcement.
Bootstrap used role="status" like this :
<div class="spinner-grow text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
and in MDN it said :
The status role is a type of live region and a container whose content
is advisory information for the user that is not important enough to
justify an alert, and is often presented as a status bar. When the
role is added to an element, the browser will send out an accessible
status event to assistive technology products which can then notify
the user about it.
There's a good article I came across that explains what needs to be done for this scenario Loading spinner accessibility
The spinner should be included inside the container. Its visibility can be toggled in relation to the aria-busy attribute. They should always be opposites, i.e, if currently loading, section[aria-busy="true"], .tn-spinner[aria-hidden="false"], once the content is loaded, toggle to false and true respectively.

Insert large amounts of Elements to DOM with Polymer Data-Binding in Dart causes lags

To be honest, I am just waiting for Günter to answer my question (lol) ^_^
Anyhow, I am writing on a project which starts with a pretty huge list of items (1500+). Some of them are used for a selection mask inside DropDowns and about 800 of them are displayed in a grid.
I tried to do the best I can to keep everything fast and smooth but loading the website takes about 20-30 seconds which is a little bit too long.
To address this issue I wanted to make use of <core-list> which allows me to render only about 8 items per DropDown instead of all of them. This would reduce the amount of items rendered for DropDowns from 700 to 32. However, I HAVE to use some observables in the DropDowns and since there is a bug accessing those I cannot make use of <core-list>.
My HTML Code for DropDowns:
<div relative flex>
<paper-input-decorator label="Committee" on-click="{{openDropdown}}" dropdown="{{committeeDropdownId}}">
<input is="core-input" value="{{committee}}">
</paper-input-decorator>
<paper-shadow absolute z="2" class="dropdown" hidden?="{{!openedState[committeeDropdownId] || committees.length < 2}}" style="width: 100%">
<div id="{{committeeDropdownId}}" style="width: 100%">
<template repeat="{{item in committees}}">
<paper-item
hidden?="{{!activeCommittees[item['v']] || !containsText(item['k'], committee)}}"
on-click="{{onItemSelected}}"
value="{{item['v']}}">{{item['k']}}</paper-item>
</template>
</div>
</paper-shadow>
</div>
As you can see, I have to access containsText(..) as well as activeCommittees inside the template which would be the template I have to use for <core-list>. With that in mind I added containsText(..) to my item class which I would use for <core-list> and added observable getters for committee and activeCommittees. Since these getters have to access the 'original' variables I declared these variables static and pretty much everything was dirty and ugly and didn't really work any longer.
First Question: So the first part of my question is, can I tweak the performance of the creation of my DropDowns WITHOUT <core-list>?
But there is more. There is a grid containing about 800 little 20x20 pixel cells. Constructing this also takes a while.
The grid HTML code looks like this:
<div vertical layout>
<template repeat="{{row in rows}}">
<div row horizontal layout>
<template repeat="{{col in row.items}}">
<template if="{{!col.dummy}}" bind="{{col.delegate as item}}">
<core-tooltip disabled?="{{!activeMEPs[item['v']]}}">
<div mep="{{item['v']}}" class="grid-item item"
low?="{{mepFactors[item['v']][0] <= 0.1}}"
style="opacity: {{mepFactors[item['v']][0]}}; background: {{color(item['v'], activeMEPs[item['v']])}};">
</div>
<div tip>
<!-- Name in Tooltip -->
<h4 style="margin: 0em 0 0.1em;">{{Database[item['v']]['k']}}</h4>
</div>
</core-tooltip>
</template>
<template if="{{col.dummy}}">
<div class="grid-item dummy"></div>
</template>
</template>
</div>
</template>
</div>
This may look more complicated than it is, but I create N rows mit M columns and fill the remaining columns with empty dummy container.
Second Question: So here comes the second part of my question, how can I increase the performance of creating my grid?
It's all about performance, right? Thanks for reading the longest post I ever made!
What core-list does to improve performance, is to only render to the DOM what is visible to the user. Everything outside the current view is only rendered when it is scrolled into view. This is usually not trivial work.
Currently development of core-/paper-elements seems a bit stale because of the transition to Polymer 0.8. I doesn't make sense to put too much effort in the 0.5 versions of the elements when a lot of work has to be redone when 0.8 is in a state that more advanced elements can be ported.
Instead of core-list you could try bwu_datagrid which also has a lot of such optimizations. BWU Datagrid also doesn't use Polymer data binding which is known to be not the fastest possible way to show data on the page. BWU Datagrid also has some issues. For example, it doesn't work well on other browsers than Chrome yet, because I also don't want to put too much effort into it before 0.8 is ready.
If you don't plan to release your application within the next weeks it might make sense to pub such performance optimizations on hold until you get them for free but it is possible that it takes some months until it becomes available.

"partial views" best practices for 'container' divs?

What is the 'best' way to handle the html markup for partial views? (which are also refreshed using AJAX) The biggest issue I run into is where to place the 'container' div...
Consider having a masterpage and a partial view.
(class="" could be interchanged with id="" depending if the partial is guaranteed to be unique, however this isn't really important to the issue i think)
Masterpage:
<div id="place1" class="placeholder">
<!-- render partial -->
</div>
Partial:
<div id="partial1" class="partial">
<!-- content -->
</div>
I feel that something isn't being done right. However I cannot remove the div in the masterpage, because I need that to 'encapsulate' the response from AJAX partial updates. And also I cannot move the div in the partial to the masterpage, because that would require to move 'partial' info to the masterpage...
How do you handle this?
I would say that it terms of the semantic description of what is happening here, of providing good hooks for styling and scripting, and also in terms of general robustness against future uses and changes, that using both divs is the best way to go.