Say I have:
<tr ng-repeat="row in rows">
<td>{{row.field1}}</td>
<td>{{row.field2}}</td>
<td>{{row.field3}}</td>
<td>{{row.field4}}</td>
<td>{{row.field5}}</td>
<td>{{row.field6}}</td>
</tr>
Now I want a conditional where I pick either field1-3 or field4-6.. So right now it's:
<tr ng-repeat="row in rows">
<td ng-if='row.isFirst'>{{row.field1}}</td>
<td ng-if='row.isFirst'>{{row.field2}}</td>
<td ng-if='row.isFirst'>{{row.field3}}</td>
<td ng-if='!row.isFirst'>{{row.field4}}</td>
<td ng-if='!row.isFirst'>{{row.field5}}</td>
<td ng-if='!row.isFirst'>{{row.field6}}</td>
</tr>
Which, when I have many columns is annoying... I'd like to somehow have the conditional outside the actual "td" Like:
<tr ng-repeat="row in rows">
<% if row.isFirst { %>
<td>{{row.field1}}</td>
<td>{{row.field2}}</td>
<td>{{row.field3}}</td>
<% else { %>
<td>{{row.field4}}</td>
<td>{{row.field5}}</td>
<td>{{row.field6}}</td>
} %>
</tr>
kinda like underscore... But it seems that angular doesn't support outside conditionals only conditionals on elements. Any ideas?
I am going to give you the “angular way” or the MVVM way, not exactly the "technical trick" you may be expecting.
Angular is an MVVM framework and therefore all your “logic” should be in the controller or the services but not in the View(html).
What you are trying to achieve is to display:
Model1 ={ Column1: ‘a’, Column2: ‘b’, Column3: ‘c’}
Or
Model2 ={ Column4: ‘d’, Column5: ‘e’, Column6: ‘f’}
If you think in terms of the models and the view you will find that is much simpler separating and performing these actions in your controller and having a lighter view which is also in the nature of the MVVM way to resolve this.
Related
First and foremost, hello! I'm new here.
I've been recently learning AngularJS and web development as I'm working so I apologize for my newbieness. I had stumbled upon a wall of sorts regarding datatable integration with AngularJS. Here's the structure of it:
<table class="datatable table table-hover">
<thead>
<tr>
<th ng-repeat="column in columns">
{{column.name}}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="form in forms | filter : {userName : activeFilter['user name']|rangeDate:activeFilter['range begin']:activeFilter['range end']:'birthDate'">
<td class="row-md-1">
<span ng-model="approvedForm.userName">
{{approvedForm.userName}}
</span>
</td>
<td class="row-md-1">
<span ng-model="approvedForm.birthDate">
{{approvedForm.birthDate}}
</span>
</td>
</tr>
</tbody>
</table>
I've to mention I make use of the filters on the client side, so they can choose the correct rows. The problem was that upon filtering some users and row-sorting with datatable, the data would get misteriously duplicated on the view, and I couldn't delete it or whatsoever. To solve it I had to take out the ng-repeat filters and filter with datatable filter support. Does anybody know what might have caused this behaviour?
Btw I'm using angularJS 1.x and datatable 1.10
Thanks!
Your data is duplicating because you bind it twice as the attribute of the HTML element and with handlebars. Remove either ng-model="..." attribute or {{...}} in your code so it would look like this:
<span>
{{approvedForm.userName}}
</span>
as #Shaishab Roy mentioned ng-model is not supposed to work with <span> so try ng-bind instead:
<span ng-bind="approvedForm.userName"></span>
This code:
<tbody v-for="contact in contacts">
<tr v-on:click="selectContact(1)">
is working well in Vue js.
But this:
<tbody v-for="contact in contacts">
<tr v-on:click="selectContact({{contact.index}})">
Doesn't seem to work well. Resulting in an error. So how can I pass a environmental variable like contact.index into the event method?
<tbody v-for="contact in contacts">
<tr v-on:click="selectContact(contact.index)">
or simply
<tbody v-for="contact in contacts">
<tr #click="selectContact(contact.index)">
v-on directive will evaluate the string as an expression. You don't have to insert extra {{ }}.
Adding to Leo's answer, if you are looking for getting index of v-for loop than you have to do following:
<tbody v-for="(contact, index) in contacts">
<tr v-on:click="selectContact(index)">
Second code resulting error that is related to interpolation
<tbody v-for="contact in contacts">
<tr v-on:click="selectContact({{contact.index}})">
Why this happening ? Because you are using templating part {{}} into v-on:click directive, which VueJS see as normal aka vanilla JS, so it can't accept the templating here {{}} - mustaches.
Previous answers give you correct and working solutions.
I would like to repeat adding table rows using a template tag with vue.js, but it doesn't work in IE11. Here is the code.
<table border="1">
<tr>
<td rowspan="2">ID</td>
<td colspan="2">Name</td>
</tr>
<tr>
<td>Height</td>
<td>Weight</td>
</tr>
<template v-repeat="items">
<tr>
<td rowspan="2">{{id}}</td>
<td colspan="2">{{name}}</td>
</tr>
<tr>
<td>{{height}}</td>
<td>{{weight}}</td>
</tr>
</template>
</table>
Any help?
See http://vuejs.org/guide/components.html#Using_Components and the warning at the end of that section:
The table element has restrictions on what elements can appear inside
it, so custom elements will be hoisted out and not render properly. In
those cases you can use the component directive syntax:
<tr v-component="my-component"></tr>.
I found a solution that changed the <template> tag to a <tbody> tag. However there would be multiple <tbody> tags in a table, I hope this is the best solution in this case.
Make a long story short, This is HTML restrictions in IE, if you want compatibility, you will have to change your HTML structure.
I found an issue with similar question like yours here: https://github.com/vuejs/vue/issues/2404
Vue renders the template into real html before compiling it, so the same html restrictions apply for Vue templates, no matter how you define it.
IE does not support inside elements like , ..
Sorry as this questions is mainly Knockout, but is in Durandal so the viewModel and some bindings my not look familiar to ko anwser contributors.
Basically my view is comprised of a table that renders server data:
view.html
<table class="table">
<tr>
<td>Company</td>
<td data-bind="text: Company"></td>
</tr>
<tr>
<td>First Name</td>
<td data-bind="text: FirstName"></td>
</tr>
<tr>
<td>Last Name</td>
<td data-bind="text: LastName"></td>
</tr>
</table>
I am on ASP.net so of course I use signalR to get my server data which represents each value in the table. This is an asynchronous call so it does not block the Durandal Composition callback which will do the Knockout bindings.
viewModel.js
define(['services/logger', 'global/session', 'jquery', 'knockout', 'knockout-mapping', 'hubs'],
function ($, ko, komapping) {
ko.mapping = komapping; // Needed
var myChildModel = function (Id) {
this.activate = function () {
$.connection.hub.start().done(function () {
con.server.getDetails(Id).done(function (data) {
ko.mapping.fromJS(data, {}, this);
console.log(data);
});
});
};
};
return myChildModel;
});
I REALLY want to take the server return and map it into the viewModel itself as shown above as I can then account for changes in the data on the server-side automatically (not included or relevant at this point), but as the viewModel does not exist prior to the binding callback
Causing the expected error:
Unable to process binding "text: function (){return Company }"
Message: Company is not defined; View: widgets/customerInfo; ModuleId:
widgets/customerInfo
To negate this issue I want to stop the Knockout applyBindings, then call it manually on my server return .done call back.
The Durandal docs do say you can stop the bindings, but does not include an example how or whether it is possible to have it apply the bindings manually when you want.
Durandal Docs
Has anyone been able to deploy this technique before, maintaining the viewModel comes from the server, and is not created then hydrated after, or has deployed a similar technique with the same outcome.
This seems like a trivial problem to solve but why not just add a conditional if above it?
<table class="table" data-bind="if: isLoaded">
<tr>
<td>Company</td>
<td data-bind="text: Company"></td>
</tr>
<tr>
<td>First Name</td>
<td data-bind="text: FirstName"></td>
</tr>
<tr>
<td>Last Name</td>
<td data-bind="text: LastName"></td>
</tr>
</table>
and just set isLoaded to false until your data is loaded async?
Just noticed some unexpected behaviour in knockout.js - Got some code that loops round an observableArray and repeats some bound HTML elements for each item in the array. One of the items is a property on a sub-object:
<tbody data-bind="foreach: Contact">
<tr>
<td data-bind="text: Name"></td>
<td data-bind="text: Project().Name"></td>
<td data-bind="text: Percentage"></td>
</tr>
</tbody>
This renders fine on page load. But if the user performs actions that end up changing the Contact array or the items inside it, Name and Project().Name update but Percentage does not, even though stepping through shows it has the correct value.
However, if I remove the unpacked sub-object:
<tbody data-bind="foreach: Contact">
<tr>
<td data-bind="text: Name"></td>
<td></td>
<td data-bind="text: Percentage"></td>
</tr>
</tbody>
Everything works perfectly.
What's going on here, and is there a fix better than using a computed observable or somesuch to calculate and hold my Project().Name value?
try this
<td data-bind="text: ko.computed(function() { return Project().Name() })"></td>
if you need 2-way binding, you can use writable computed