In polymer-dart how do I count inside a repeating template - templates

Say I've got a repeating template:
<template bind repeat id='my-template'>
This is the bound value: <span id="#myid[x]"> {{}} </span>
</template>
what can I replace [x] with that will be unique? Access to the loop counter would do the trick, but I'm open to suggestions.

I'm adding some utilities to Fancy Syntax (Polymer.dart's default binding syntax now) to help with this, but the basic outline is to run your collection though a filter that will add indices and return a new Iterable.
Here's some code that will do it now though:
import 'package:fancy_syntax/fancy_syntax.dart';
import 'package:mdv/mdv.dart';
Iterable<IndexedValue> enumerate(Iterable iterable) {
int i = 0;
return iterable.map((e) => new IndexedValue(i++, e));
}
class IndexedValue<V> {
final int index;
final V value;
IndexedValue(this.index, this.value);
}
main() {
query('#my-template')
..bindingDelegate = new FancySyntax(globals: {
'enumerate': enumerate,
})
..model = ['A', 'B', 'C'];
}
<template bind id='my-template'>
<template repeat="{{ item in this | enumerate }}">
This is the bound value: <span id="#myid-{{ item.index }}">{{ item.value }}</span>
</template>
</template>
I'm trying to get a bunch of utilities like Python's itertools into a library for uses like this. I'll update when they're available.

Related

Angular validation for fields to be valid but not required

I have the following in my template:
<div class="form-group">
<label for="work_phone">Work Phone</label>
<input type="text"
class="form-control"
name="workPhone"
ng-class="{'borderRed': contactInformation.workPhone.$invalid && contactInformation.submitted}"
ng-model="controller.contactInformation.workPhone"
ng-pattern="/^\d+$/"
maxlength="10"
id="work_phone">
<small class="error"
ng-show="contactInformation.workPhone.$invalid && !contactInformation.workPhone.$pristine && contactInformation.submitted">
That's not a valid phone number (only numerics are allowed)!
</small>
</div>
Conditions:
1. If the field is blank/untouched, the form should stay valid.
2. If there is any value in the field then it should be validated against the regex provided in ng-pattern.
Looks very trivial. I know. But for some stupid reason, unable to find a solution
So if i understand your problem you want allow only numerics you can use this directive to block every other caracters :
.directive('onlyDigits', function () {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, element, attr, ctrl) {
function inputValue(val) {
if (val) {
var digits = val.replace(/[^0-9]/g, '');
if (digits !== val) {
ctrl.$setViewValue(digits);
ctrl.$render();
}
return parseInt(digits,10);
}
return undefined;
}
ctrl.$parsers.push(inputValue);
}
};
});
And add the directive to your input, it's faster and you haven't to use ng-pattern :
<input type="text"
class="form-control"
name="workPhone"
maxlength="10"
id="work_phone" onlyDigits>
Your form currently stays valid to begin, because you're checking for $pristine. Try using $setPristine() when the form is empty to reset it, so no longer gets the error class.
You may change your regex so that it allows empty strings:
ng-pattern="/^\d*$/"

knockout.js, afterrender function doesnt work as expected

I got an issue with my code, im using hljs to highlight my code snippets which im using. I wrote a template system, as example the general input would be this:
<codeexample params="type: html">
<div style="example_class">Example code</div>
</codeexample>
My template interpreter:
<template id="codeexample">
<div class="code">
<pre><code data-bind="attr: {class: type}, template: { nodes: $componentTemplateNodes, afterRender: $root.handleCode}, visible: false ">
</code></pre>
</div>
</template>
My handleCode function:
this.handleCode = function(element) {
var preCodeTags = $(element).find('pre code');
preCodeTags.each(function(i, block) {
hljs.highlightBlock(block);
block.show(100);
});
}
The problem is that the afterRender function is called already before the template is rendered to my actual template, i used to add a console.log($(element).find('pre code')); which had the result that the length was 0.
[prevObject: jQuery.fn.jQuery.init[3], context: undefined, selector:
"pre code", constructor: function, init: function…]
context: undefined
length: 0
Shouldnt the function afterRender run exactly after the render process?
Is there a known work around? When I use a timeout for 200ms, it works fine, but this is the worst solution in my opinion.
Your afterRender handler isn't quite right. The parameter (element in your case) is actually an array of all elements rendered. From the documentation:
viewModel.myPostProcessingLogic = function(elements) {
// "elements" is an array of DOM nodes just rendered by the template
// You can add custom post-processing logic here
}
So it's not finding the code element successfuly. You could do this instead:
this.handleCode = function(elements) {
var preCodeTags = $(elements).filter('div').find('pre code');
preCodeTags.each(function(i, block) {
hljs.highlightBlock(block);
block.show(100);
});
}

How do you know when templates have been initialized in polymer dart?

The polymer js docs say you have to listen for the WebComponentsReady event to know when the polymer elements have been set up. What's the equivalent in Dart?
Here's my template:
<template id="order_name" bind repeat>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#order_list" href="#collapseOne">
{{commonName}} ({{scientificName}})
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
...
</div>
</div>
</div>
</template>
And here's main:
void main() {
OrderList().then((order_data) {
query("#order_name").model = order_data;
print (queryAll(".accordion-heading")); //null
}).catchError((err) => print(err));
query("#my-button").onClick.listen((Event e) {
print (queryAll(".accordion-heading")); //[div,div]
});
}
OrderList is a wrapper around HttpRequest.getString() and returns a future. My thought was to use an event like WebComponenentsReady to know when the template had been fully instantiated. The base question is how can I get at the .accordion-heading divs in main so I can attach listeners to them?
I assume that you are using boot.js. if you are, they should be initialized by the time you program enters main().
According to the spec (https://www.dartlang.org/articles/web-ui/spec.html#main-script):
...you cannot query for children of conditional and iteration nodes. ...To retrieve a component instance you need to defer queries until the end of the event loop, for example using a Timer.run(f).
So the code above needs to be modified like this:
void main() {
OrderList().then((order_data) {
query("#order_name").model = order_data;
print (queryAll(".accordion-heading")); //null
Timer.run( () => print (queryAll(".accordion-heading"))); //[div,div]
}).catchError((err) => print(err));
query("#my-button").onClick.listen((Event e) {
print (queryAll(".accordion-heading")); //[div,div]
});
}

Go Templates: Are Nested Ranges Possible?

This one is seemingly simple but it's driving me insane.
How does one go about referencing a struct element higher in the scope within a nested range in golang templates?
Example:
type Foo struct {
Id string
Name string
}
type Bar struct {
Id string
Name string
}
var foos []Foo
var bars []Bar
// logic to populate both foos and bars
In the template:
{{range .foos}}
<div>Foo {{.Name}}</div>
<div>
{{range ..bars}}
<div>Bar {{.Name}} <input type="text" name="ids_{{..Id}}_{{.Id}}" /></div>
{{end}}
</div>
{{end}}
Obviously ..bars and ..Id don't work, but hopefully my intent is clear. I'd like to iterate through all combinations of Foo and Bar and generate a form element with a name build by both the Foo's Id and the Bar's Id.
The problem is that it seems it is impossible to:
Access bars from inside the scope of the foos range scope
Access Foo's Id from inside the bar's range scope
I have a temporary workaround to this by putting a bunch of redundant fields in both structs, but this seems very ugly to me, violates DRY, and in general feels very wrong.
Is there any way with golang templates to do what I'd like to do?
Yes. I feel as if not finding a solution comes from not reading the text/template package closely enough. If you are using html/template, the syntax is the same (and they tell you to read text/template ;)). Here is a complete working solution for what you might want to do.
Go file:
package main
import (
"bytes"
"io/ioutil"
"os"
"strconv"
"text/template"
)
type Foo struct {
Id string
Name string
}
type Bar struct {
Id string
Name string
}
var foos []Foo
var bars []Bar
func main() {
foos = make([]Foo, 10)
bars = make([]Bar, 10)
for i := 0; i < 10; i++ {
foos[i] = Foo{strconv.Itoa(i), strconv.Itoa(i)} // just random strings
bars[i] = Bar{strconv.Itoa(10 * i), strconv.Itoa(10 * i)}
}
tmpl, err := ioutil.ReadFile("so.tmpl")
if err != nil {
panic(err)
}
buffer := bytes.NewBuffer(make([]byte, 0, len(tmpl)))
output := template.Must(template.New("FUBAR").Parse(string(tmpl)))
output.Execute(buffer, struct {
FooSlice []Foo
BarSlice []Bar
}{
FooSlice: foos,
BarSlice: bars,
})
outfile, err := os.Create("output.html")
if err != nil {
panic(err)
}
defer outfile.Close()
outfile.Write(buffer.Bytes())
}
Note: You can probably do something to not load the file into an intermediate buffer (use ParseFiles), I just copied and pasted some code that I had written for one of my projects.
Template file:
{{ $foos := .FooSlice }}
{{ $bars := .BarSlice }}
{{range $foo := $foos }}
<div>Foo {{$foo.Name}}</div>
<div>
{{range $bar := $bars}}
<div>Bar {{$bar.Name}} <input type="text" name="ids_{{$foo.Id}}_{{$bar.Id}}" /></div>
{{end}}
</div>
{{end}}
The two morals of this story are
a) use variables in templates judiciously, they are beneficial
b) range in templates also can set variables, you do not need to rely solely on $ or .

angularjs if statements?

So I'm running through the tutorial for AngularJS:
I have an array defined in the controller and i'm returning different points in the array by calling when i'm looping through ng-repeat {{feature.name}} {{feature.description}}
What i don't understand is lets say i have a third point in the array called "importance" and it's a number from 1 to 10. I don't want to display that number in the html but what i do want to do is apply a different color to the feature if that "importance" number in the array is 10 vs 1
so how do i write an if statement to do this:
i.e.
<p style="**insert if statement: {{if feature.importance == 10}} color:red; {{/if}} **">{{feature.description}}</p>
no idea if that's right but that's what i want to do
I do not think there is if statement available.
For your styling purpose, ng-class can be used.
<p ng-class="{important: feature.importance == 10 }">
ng-switch is also convenient.
-- update --
take a look at:
https://stackoverflow.com/a/18021855/1238847
angular1.2.0RC seems to have ng-if support.
Actually there is a ternary operator in Angular 1.2.0.
<p style="{{feature.importance == 10 ? 'color:red' : ''}}">{{feature.description}}</p>
I think the answer needs an update.
Previously you could use ngIf directive from AngularUI project (code here if you still want to download it), bad news is that it's not maintained any more.
The good news is that it has been added to the official AngularJS repo (unstable branch) and soon will be available in the stable one.
<div ng-if="something"> Foo bar </div>
Will not just hide the DIV element, but remove it from DOM as well (when something is falsy).
ng-class is probably the best answer to your issue, but AngularUI has an "if" directive:
http://angular-ui.github.com/
search for:
Remove elements from the DOM completely instead of just hiding it.
I used "ui-if" to decide if I should render a data value as a label or an input, relative to the current month:
<tbody id="allocationTableBody">
<tr ng-repeat="a in data.allocations">
<td>{{a.monthAbrv}}</td>
<td ui-if="$index < currentMonth">{{a.amounts[0]}}</td>
</tr>
</tbody>
In the case where your priority would be a label, you could create a switch filter to use inside of ng-class as shown in a previous SO answer : https://stackoverflow.com/a/8309832/1036025 (for the switch filter code)
<p ng-class="feature.importance|switch:{'Urgent':'red', 'Warning': 'orange', 'Normal': 'green'}">...</p>
You can also try this line of code below
<div class="{{is_foo && foo.bar}}">
which shows foo.bar if is_foo is true.
This first one is a directive that evaluates whether something should be in the DOM only once and adds no watch listeners to the page:
angular.module('setIf',[]).directive('setIf',function () {
return {
transclude: 'element',
priority: 1000,
terminal: true,
restrict: 'A',
compile: function (element, attr, linker) {
return function (scope, iterStartElement, attr) {
if(attr.waitFor) {
var wait = scope.$watch(attr.waitFor,function(nv,ov){
if(nv) {
build();
wait();
}
});
} else {
build();
}
function build() {
iterStartElement[0].doNotMove = true;
var expression = attr.setIf;
var value = scope.$eval(expression);
if (value) {
linker(scope, function (clone) {
iterStartElement.after(clone);
clone.removeAttr('set-if');
clone.removeAttr('wait-for');
});
}
}
};
}
};
});
This second one is a directive that conditionally applies attributes to elements only once without watch listeners:
i.e.
<div set-attr="{ data-id : post.id, data-name : { value : post.name, condition : post.name != 'FOO' } }"></div>
angular.module('setAttr',[]).directive('setAttr', function() {
return {
restrict: 'A',
priority: 100,
link: function(scope,elem,attrs) {
if(attrs.setAttr.indexOf('{') != -1 && attrs.setAttr.indexOf('}') != -1) {
//you could just angular.isObject(scope.$eval(attrs.setAttr)) for the above but I needed it this way
var data = scope.$eval(attrs.setAttr);
angular.forEach(data, function(v,k){
if(angular.isObject(v)) {
if(v.value && v.condition) {
elem.attr(k,v.value);
elem.removeAttr('set-attr');
}
} else {
elem.attr(k,v);
elem.removeAttr('set-attr');
}
});
}
}
}
});
Of course your can use dynamic versions built into angular:
<div ng-class="{ 'myclass' : item.iscool }"></div>
You can also use the new ng-if added by angularjs which basically replaces ui-if created by the angularui team these will conditionally add and remove things from the DOM and add watch listeners to keep evaluating:
<div ng-if="item.iscool"></div>
What also works is:
<span>{{ varWithValue || 'If empty use this string' }}</span>