Angularjs - How to apply different class in <tr> conditionally to repeat directive - indexing

I need to apply a different class to a <tr> according to the $index of the repeat directive. For example
<table>
<tr ng-repeat="model in list" class="xxx">
<td>...</td>
<tr>
</table>
I need to apply a different style to <tr> depending on whether the index is even and odd.
How could I solve this?

Normally you would use ngClassOdd (http://docs.angularjs.org/api/ng.directive:ngClassOdd) and ngClassEven (http://docs.angularjs.org/api/ng.directive:ngClassEven) directives like this:
<tr ng-repeat="item in items" ng-class-odd="'class1'" ng-class-even="'class2'">
Here is the jsFiddle: http://jsfiddle.net/pkozlowski_opensource/hNHJ4/1/
Unfortunately there is an issue where the mentioned directives are not working correctly when rows are removed: https://github.com/angular/angular.js/issues/1076
As a work around you can use the ngClass directive (http://docs.angularjs.org/api/ng.directive:ngClass) with the $index variable exposed by a repeater:
<tr ng-repeat="item in items" ng-class="{class1 : $index%2==0, class2 : !($index%2==0)}">
Here is the jsFiddle: http://jsfiddle.net/pkozlowski_opensource/am7xs/
It is not super-clean, but could be improved (for example, by exposing a function in a root scope, something like:
ng-class="getClass($index,'class1','class2')"
till the mentioned bug is fixed

If this is just for styling you can just use CSS
tr:nth-child(odd) { ... }
tr:nth-child(even) {...}
see http://jsfiddle.net/5MSDC/ for an example

Related

Headers in column using dojo

Is there a way to bring headers in the column and on click of the header, the attributes associated with the header in a different column using Dojo?
Thanks
Kumar
you can use the event onHeaderCellClick
onHeaderCellClick: function()
{
console.log("do what you want");
}
to add the header, you can do it easily in declarative way like this:
<table data-dojo-type="dojox.grid.DataGrid">
<thead>
<tr>
<th field="fieldName" width="200px">Column Header</th>
</tr>
</thead>
</table>
If you are using declarative way you can use the attribute onHeaderCellClick to your table, onHeaderCellClick="func" call function func().

How to assign 50% of participants to one survey and 50% to another

I am using the "Survey Link" template to create a project on Mechanical Turk.
I am running an A/B test. I would like to direct 50% of workers to one link, and 50% to another link.
How do I do this?
From the "Design Layout" page, click on "Source". This will let you edit the html/javascript/css for the survey.
You'll find a <table> element with a <tbody> element. Change the <tbody> element to this:
<tbody>
<tr class="survey-one">
<td><label>Survey link:</label></td>
<td><a class="dont-break-out" href="http://link-to-survey-1">http://link-to-survey-1</a></td>
</tr>
<tr class="survey-two">
<td><label>Survey link:</label></td>
<td><a class="dont-break-out" href="http://link-to-survey-2">http://link-to-survey-2</a></td>
</tr>
</tbody>
This simply adds another row to the table for the link for your second survey. Note the link-to-survey-1 and link-to-survey-2 that you'll need to replace with your own links.
A bit lower in the file, you'll see the <style> element. Add this to it:
.survey-hidden {
display: none;
}
And a bit lower, you'll see a <script> element. At the bottom of it, right before the });, add the following javascript:
var surveyToHide = (Math.random() >= 0.5) ? '.survey-one' : '.survey-two';
$(surveyToHide).addClass('survey-hidden');
This randomly picks one of your suveys, and makes it hidden, so that the worker sees only one.

VueJS - v-for and attributes on the parent Element

I'm working with a table display and am using vueJS to render a group of rows inside of a table. The bindings inside of the <tr> work fine, but I can't figure out how to bind say an attribute that lives on the parent <tr> that hosts the v-for directive:
<tr v-for="detailItem in itemList" data-key="{detailItem.pk}}">
<td>{{detailItem.cdesc}}</td>
<td>{{(detailItem.nnetunits * 1).toFixed(2)}}</td>
...
</tr>
In this code the inner items on the <td> bind just fine, but how would you get the data-key bound?
With Vue 2 you don't use interpolation in attributes, you use the attribute binding syntax.
<tr v-for="detailItem in itemList" v-bind:data-key="detailItem.pk">
Or the shortcut
<tr v-for="detailItem in itemList" :data-key="detailItem.pk">

Aurelia customAttribute to toggle input edit

I need some help in figuring out the best way to create a customAttribute that will allow for an easy edit-toggle. Here is what I'm looking for:
<tr toggle-edit>
<td edit-hide>${model.name}</td>
<td edit-show><input type="text" value.bind="model.name"></td>
<td><button edit-trigger>Edit</button></td>
</tr>
So basically I want a customAttribute named toggleEdit that will look for edit-trigger attribute and add an event listener to it that will toogle a variable true/false and depending on it will either show or hide the elements that have edit-hide / edit-show.
I'd prefer to not travers the DOM inside the element to find these attributes as it feels jQuerish, is this achievable?
I want to have a customAttribute like this because I have at least 10 elements that will use an edit button and having a variable for each one of them and then use if.bind seems like a bad idea. I could always do inside of the template itself through click.delegate="myShowVar = !myShowVar" but as far as I know puting logic inside html is a bad practice (coming from an angular background).
I would add a plunker/codepen but because of the whole compilation and libraries dependencies this does not seem like an easy task.
Many thanks for any ideas.
Use the contenteditable attribute
I recommend against trying to have a custom attribute automagically handling this for you. You'll probably run into more problems than you'll solve this way. Instead, I recommend that you create an editable property in your view model and bind to it.
The contenteditable attribute is a standard HTML attribute that allows for editing the content of HTML elements, such as DIVs, and is supported out of the box with Aurelia. I recommend leveraging it if it will meet your needs. Here's how:
table.html
<td contenteditable.bind="editable"></td>
<td><button click.delegate="editable = !editable"></td>
Full running gist here: https://gist.run/?id=c4e716f21f4f9c15a9346cfacbdae74b
Since my <tr></tr> turned out to be a 14 line code (with some animation on toggling) I decided it was best to create a customElement out of it. The problem I ran on was that customElements don't really work as table elements (similar as in other frameworks). The soultion to this is to use a as-element attribute.
Inside of the customElement I used contenteditable which is actually a better solution than using if.bind since swapping between input and a div produces a jumping effect because of the difference in styles (which of course could be circumnavigated by applying certain style to them but contenteditable works out-of-the-box).
This is more or less what I created (parent.html):
<tr as-element="my-custom-row"
title="My first row"
is-editable="true"
model.two-way="myModel.name"
value-changed-callback.call="updateModel(myModel)">
</tr>
And inside my-custom-row.html:
<template>
<td>${title & oneTime}</td>
<td>
<div contenteditable.one-way="editingEnabled ? 'true' : 'false'"
blur.trigger="valueChanged(model)"
textcontent.two-way="model">
</div>
<div class="my-class" class.one-way="editingEnabled ? 'my-class--active' : ''"></div>
</td>
<td>
<span class="edit-icon"
click.delegate="editingEnabled = !editingEnabled"
if.one-time="isEditable">
</span>
</td>
</template>
This way I don't have to create a variable for each edit since editingEnabled is unique to each customElement.
As I side note, I think it's better to be more explicit and to use one-way/two-way/one-time instead of bind since it's clear what is happening.
I will also provide the corresponding js for a full answer(my-custom-row.js):
import { bindable } from 'aurelia-framework';
export class MyCustomRow {
#bindable model;
#bindable title;
#bindable isEditable;
#bindable valueChangedCallback;
constructor() {}
valueChanged(modelValue) {
this.valueChangedCallback({ modelValue })
}
}

Angular-repeat display column IF equal to a value

I am using angularJS to display my result set into a table, that is filterable with totals etc. I was wondering if it would be possible to display a value based on another value if it is = to something. here is an example:
<tr ng-repeat="c in data">
<td>{{c.type}}</td> //expects either 'fixed' or 'hourly'
<td>{{c.fixed_rate}}</td>
<td>{{c.hourly_rate}}</td>
</tr>
Therfore are you able to only display the fixed value if type is fixed, and hourly if the type is hourly without using any JQuery to hide elements?
My mind is kind of stumped on this as I am just a few months in with angular.
Data is pulled from a database* so if there is an SQL option I am all for it.
You could do something like this:
<tr ng-repeat="c in data | filter: filterHourlyOrFixed">
<td>{{c.type}}</td>
<td ng-if="c.type == 'fixed'">{{c.fixed_rate}}</td>
<td ng-if="c.type == 'hourly'">{{c.hourly_rate}}</td>
</tr>
If you want to filter by only those two values, add this function to your controller:
$scope.filterHourlyOrFixed = function (item) {
return item.type === 'fixed' || item.type === 'hourly';
};
If you do not want to filter by the value, remove | filter: filterHourlyOrFixed from the ng-repeat.
Also, when you have some time, do a little reading through the docs for ngIf, ngShow, ngHide, and ngFilter. You'll probably be using these repeated. Also, pay attention to the differences in how ng-if, ng-show, and ng-hide manipulate the DOM to achieve similiar results.
The differences are subtle, but important.
Use ng-if to remove or recreate parts of the DOM based on an expression. for example:
<tr ng-repeat="c in data">
<td>{{c.type}}</td> //expects either 'fixed' or 'hourly'
<td ng-if="c.type=='fixed'">{{c.fixed_rate}}</td>
<td ng-if="c.type=='hourly'">{{c.hourly_rate}}</td>
</tr>
You could also use a filter, if you are rendering identical DOM but want to exclude certain elements.
You could try something like this:
<tr ng-repeat="c in data">
<td ng-if="c.type =='fixed'">Fixed</td>
<td ng-if="c.type =='hourly'">Hourly</td>
<td ng-if="c.type =='fixed'">{{c.fixed_rate}}</td>
<td ng-if="c.type =='hourly'">{{c.hourly_rate}}</td>
</tr>
Hope this helps!
http://embed.plnkr.co/Wes1Uf1OCCmKYa5wTP5s/preview