Drilldown functionality with AngularJS using ng-repeat property and jQuery - javascript

I want to do the exact same thing as this Fiddle (The example is mine) but using angular. In the normal HTML I have a parent tr with its own child tr so when I run the example I can see
that the child records that are related to its parent tr
Then I start doing this in Angular but now Im confused because I'm using ng-repeat and a JSON structure to populate the data so now I only have this piece of code, I put this as the parent but I don't know how to deal with the "child":
<tbody>
<tr ng-repeat="d in category" class="parent">
<td class="expand"></td>
<td ng-bind="d.cat"></td>
<td ng-bind="d.LW$"></td>
<td ng-bind="d.LW"></td>
<td ng-bind="d.L4W"></td>
<td ng-bind="d.L13W"></td>
<td ng-bind="d.L52W"></td>
</tr>
</tbody>
Here is my code with the angular version: https://jsfiddle.net/228wkfej/

Related

How to render a vue component with TR as the root element?

I don't have much experience with Vue and facing an issue with redering a component with root as TR element.
I read this in the docs https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats and tried adding the component using is property, but that didn't help either.
Check the code below.
Vue.component('car',{
props: ['number']
})
new Vue({
el: "#app"
})
<div id="app">
<table>
<tr is='car' inline-template number='123'>
<tr>
<td>car no</td>
<td>{{number}}</td>
</tr>
</tr>
<tr is='car' inline-template number='456'>
<tr>
<td>car no</td>
<td>{{number}}</td>
</tr>
</tr>
</table>
</div>
This errors out:
Error compiling template:
Inline-template components must have exactly one child element.
How can I fix this? Appreciate the help.
Fiddle https://jsfiddle.net/8d65gvua/
Update ----
More findings
If i wrap my tr in a template it works
<tr is='car' inline-template number='456'>
<template>
<tr>
<td>car no</td>
<td>{{number}}</td>
</tr>
<template>
</tr>
I have no clue why. Shouldn't the issue with tr be fixed with using the is property? Why do we need to do this?
I've never used inline-template before, my guess is that you are using it to pass the number to your "inner template"? You can achieve the same thing by using slots. (Reference)
I did a test but using slots instead, which I think it's a better way to cater for passing "inner templates". Also given the below warning in the documentation with regards to inline-template I would opt for slots.
However, inline-template makes the scope of your templates harder to
reason about. As a best practice, prefer defining templates inside the
component using the template option or in a <template> element in a
.vue file.
Example
Vue.component('my-row', {
template: `
<tr>
<slot></slot>
</tr>
`
})
The above is a component to define a single table row. The <slot> element is basically a placeholder for any content you want to pass into this template.
Usage
<div id="app">
<table>
<tr
is="my-row"
v-for="todo in todos"
>
<td>{{ todo.text }}</td>
</tr>
</table>
</div>
What will happen here is that <td>{{ todo.text}}</td> will be placed instead of the <slot> element in the my-row component. You can have multiple <td> elements, whatever content you put in the my-row will appear instead of <slot>.
JS Fiddle: https://jsfiddle.net/x793nub6
PS: Slots!
I don't want to make the answer too long, but keep in mind that with slots you can have a super customisable components, of course this all depends on your needs. But I would suggest having a look at the documentation and trying out a few expirements.
Update - If you still want to use inline-template
I went through the JS Fiddle you shared once more and realised what's the issue you are having. Basically vue is saying that one child needs to be passed. I guess there's some mixup since there's a <tr> nested in another <tr>. To fix it wrap the inner <tr> with a <template> element.
From:
<tr is='car' inline-template number='123'>
<tr>
<td>car no</td>
<td>{{number}}</td>
</tr>
</tr>
To:
<tr is='car' inline-template number='456'
<template>
<tr>
<td>car no</td>
<td>{{number}}</td>
</tr>
</template>
</tr>

How to create grouped table rows in Marionette 3

I have a collection of models which I have passed into Marionette to generate a HTML table, but every row of the table needs to be expandable with additional hidden details.
This is very much like this question aimed at the deprecated CompositeView: How to show CompositeView with multiple children view in Backbone Marionette
The HTML structure that I'm trying to reproduce:
<table>
<thead>
<tr>
<th>Qty</th>
<th>Product</th>
<th>Price</th>
</tr>
</thead>
<!-- first item -->
<tbody>
<tr class="row-parent">
<td>1x</td>
<td>Fruit Bowl</td>
<td>£9.99</td>
</tr>
<tr class="row-child">
<td colspan="3">Some additional hidden info</td>
</tr>
</tbody>
<!-- second item -->
<tbody>
<tr class="row-parent">
<td>2x</td>
<td>Banana</td>
<td>£0.50</td>
</tr>
<tr class="row-child">
<td colspan="3">Some additional hidden info</td>
</tr>
</tbody>
</table>
As each group can be an ItemView with a tagName of tbody the grouping isn't so much of the issue. It's the injecting the CollectionView into the table which I can't figure out.
I'm ending up with tbody inside the CollectionView's el. I'm not too sure how to get around that?
JSFiddle here: https://jsfiddle.net/mzsgo3ay/5/

Render HTML into an AngularJS view

I have an angular app with one controller and one view, in my view I have a navigation bar with four options, the thing is that I cant create more html files, I need to work all in the index.html file that is under my app folder, in that file I have three tables where I bind some data coming from a WS that I call in three differente functions in my controller file, for example like this:
<table class="table table-bordered" ng-if="topTable === 'topCategory'">
<tbody>
<tr ng-repeat="d in data">
<td ng-bind = "d.Name">
<td ng-bind = "d.Email">
</tr>
</table>
<table class="table table-bordered" ng-if="topTable === 'topBrand'">
<tbody>
<tr ng-repeat="d in data">
<td ng-bind = "d.Name">
<td ng-bind = "d.Email">
</tr>
</table>
I hide the firs two and depending on the radio button selection that I have other tables appears.
My issue is that as I mentioned before, my navigation bar has four options where I have three more tables for each option, so I saw something about directives but Im new to angular and I want to know how to render all the html that I have in my current view without losing functionality and allowing the app to render the correct data depending on the selected option of the nav bar.
I really need help on this.
Thanks

need advice on dust temmplate

I am completely new to dust (linkedin), just working on my first little template. After writing it the obvious (but long) way I thought of a way to optimize using an inline partial.
The long version looks like this:
{#parcours}<tr class="pcsel_pc" id="{id}">
<td class="pcsel_exp_btn"><a href="#" class="list{?exp}Hide{:else}Exp{/exp}Btn">
<span class="glyphicon glyphicon-{?exp}minus{:else}plus{/exp}"></span></a></td>
<td class="pcsel_col">{name}</td><td class="pcsel_col pcsel_num">{count}</td>
</tr>
{?exp}
{#variants}
<tr class="pcsel_var{?sel} pcsel_sel{/sel}" id="{id}" >
<td class="pcsel_col"> </td><td class="pcsel_var pcsel_col">{name}</td>
<td class="pcsel_col pcsel_num">{count}</td>
</tr>
{/variants}
{:else}
{#variants}
<tr class="pcsel_var pcsel_hide" id="{id}" >
<td class="pcsel_col"> </td><td class="pcsel_var pcsel_col">{name}</td>
<td class="pcsel_col pcsel_num">{count}</td>
</tr>
{/variants}
{/exp}
{/parcours}
Explanation:
I have a context parcours that contains an inner context variants. If the variable exp does not exist in the outer context, I want to use a class pcsel_hide in the inner context.
This solution works but the code for the inner context is contained twice which is kind of stupid. So I thought of a way to use an inline partial which is conditionally set in the outer context and used in the inner context:
{#parcours}<tr class="pcsel_pc" id="{id}">
<td class="pcsel_exp_btn"><a href="#" class="list{?exp}Hide{:else}Exp{/exp}Btn">
<span class="glyphicon glyphicon-{?exp}minus{:else}plus{/exp}"></span></a></td>
<td class="pcsel_col">{name}</td><td class="pcsel_col pcsel_num">{count}</td>
</tr>
{?exp}{<hide/}{:else}{<hide} pcsel_hide{/hide}{/exp}
{#variants}
<tr class="pcsel_var{+hide/}{?sel} pcsel_sel{/sel}" id="{id}" >
<td class="pcsel_col"> </td><td class="pcsel_var pcsel_col">{name}</td>
<td class="pcsel_col pcsel_num">{count}</td>
</tr>
{/variants}
{/parcours}
This version is nice and short, but it doesn't seem to do the job. I see the class pcsel_hide all the time even if the outer context contains exp and thus uses the correct classes.
Any ideas ?
This is because inline partials are statically evaluated before template rendering begins. The last version of an inline partial defined with the same name wins.
Inline partials cannot be conditionally evaluated like this. What you probably want instead is to use a logic helper like {#eq}.

Granular rendering control inside a knockout.js `foreach` control binding

I am new to knockout, and I can't seem to find this problem stated or documented elsewhere, though I suspect I might be missing something.
I have a foreach in my knockout template HTML as such:
...
<tbody data-bind="foreach: cfeeds">
<tr class="datarow" data-bind="css:{danger:discovered()==false}">
<td><a title="View this feed" data-bind="text: name,attr: {href: view_url}"></a></td>
<td data-bind="text: description, css:{'text-danger':discovered()==false}"></td>
<td class="text-center" data-bind="text: sched_type"></td>
<td class="text-center" data-bind="text: sched_data"></td>
<td class="text-center" data-bind="text: moment(last_poll()).calendar()"></td>
<td class="text-right">
<div class="feedgraph">
<!-- D3 chart container -->
</div>
</td>
</tr>
</tbody>
...
In the last DIV with class="feedgraph", I add (in this case) a D3 chart, which works fine when the DIV is outside the foreach. However, it appears that knockout will rerender the entire TR every time the JSON poll returns, whether the JSON contains a changed value or not, and my .feedgraph div gets emptied.
Relevant viewmodel blocks:
...
self.cfeeds = ko.observableArray([]);
...
self.loadFeeds = function() {
postJSON(ajax_uri+'get_site_feeds/',{'site_id':selected_site_id},function(d){
self.cfeeds.removeAll();
$.each(d['configured_feeds'],function(i,v) {
self.cfeeds.push(new Feed(v));
});
setTimeout(vm.loadFeeds,5000);
});
};
...
$(function(){
vm.loadFeeds();
});
...
It seems to me that the knockout rendering should occur at the atomic TD level only when a bound value changes, rather than at the TR level as it appears to be doing.
Hence, my question is: Is there a way to keep knockout from rerendering the entire row in a foreach, and instead only rerender the TD cells that have a data-bind attribute and leave my D3 charts alone?

Categories

Resources