I am running into an interesting issue where my Dust.js template is not honoring an exists conditional.
My data looks like this:
{"guaranteedHistory": [
{
"depositDate": "2017-08-31T00:00:00.000-0500",
"interestRate": 515.5,
"maturityDate": "2017-08-31T00:00:00.000-0500",
"beginningBalance": 874757257.4,
"deposits": 4.25,
"transferIn": 75.7,
"investmentReturn": 52.71,
"amtReinvested": 5.5,
"maturityWithdrawal": 6.66,
"surrenderCharge": 7.77,
"endingBalance": 8.88,
"surrenderValue": 5735.56
}
],
}
Template (Doesn't work):
{?guaranteedHistory}
<table id="a">
<thead>
<tr>
<th> </th>
<th>What happened this period</th>
<th></th>
</tr>
</thead>
</table>
{:else}
<table id="b">
<thead>
<tr>
<th>Deposits</th>
<th>Dividends</th>
<th>Investment return</th>
</tr>
</thead>
</table>
{/guaranteedHistory}
The issue is that no matter what happens, the template will only display everything in the else conditional UNLESS inside the exists I output a value inside guaranteedHistory...
Template (This works):
{?guaranteedHistory}
{guaranteedHistory[0].depositDate}
<table id="a">
<thead>
<tr>
<th> </th>
<th>What happened this period</th>
<th></th>
</tr>
</thead>
</table>
{:else}
<table id="b">
<thead>
<tr>
<th>Deposits</th>
<th>Dividends</th>
<th>Investment return</th>
</tr>
</thead>
</table>
{/guaranteedHistory}
I was not able to find any way to get around this. I also could not duplicate this issue within a dev mode on dustjs.com, it works correctly there. Could anyone please help or tell me what could possibly be going wrong based on the provided information?
There is no reason that this shouldn't work correctly as you've described it. In addition, the compiled body_0 you provided is definitely correct.
So, if this really is happening, the only possible reasons are:
You aren't rendering the template you think you are. This seems unlikely if you're compiling and rendering yourself.
The value of guaranteedHistory isn't what you think it is. Because you are testing your template on http://www.dustjs.com/test/test.html and it works properly there, this is my guess.
So, this suggests to me that you have a race condition, and that you're trying to render with guaranteedHistory before it has been set (via some callback, Promise, etc).
Dust 2.7.2 doesn't resolve Promises in exists blocks so this may be what you're hitting. You can use the trunk tip if you need to until 2.8 is released.
Related
I'm trying to iterate through table rows and get each row which includes a specific value,
but it doesn't work for me.
I'm using .each() to iterate the rows and .within() on each $el,
inside that, I use cy.get('td').eq(1).contains('hello') but I the get assertion error:
Timed out retrying: Expected to find content: 'hello' within the element: <td> but never did.
when I console.log cy.get('td').eq(1) it yields the desired cell in each row and the test passes, so I don't understand why chaining .contains() doesn't work...
it('get element in table', () => {
cy.visit('http://localhost:3000/');
cy.get('tbody tr').each(($el) => {
cy.wrap($el).within(() => {
cy.get('td').eq(1).contains('hello') // contains() doesn't work
})
})
});
<table>
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tbody>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>hello</td>
<td>$80</td>
</tr>
<tr>
<td>$10</td>
<td>hello</td>
</tr>
</tbody>
</table>
should('have.text', text) should work
cy.get('td').eq(1).should('have.text', 'hello')
If there's whitespace around text, use contain.text
cy.get('td').eq(1).should('contain.text', 'hello')
The simple answer is: don't :)
To be more specific use html attribute selection instead. The convention is to have an attribute named data-cy. Furthermore, I discovered it convenient to have a data-cy-identifier for when selecting specific rows. Since I'm not sure what you're trying with your code, I'll use a similar example that can hopefully get you going:
<table data-cy="expences">
<tr>
<td data-cy="month">January</td>
<td data-cy="price">$100</td>
</tr>
<tr data-cy="discounted">
<td data-cy="month">Feburary</td>
<td data-cy="price">$80</td>
</tr>
<tr data-cy="discounted">
<td data-cy="month">March</td>
<td data-cy="price">$10</td>
</tr>
</table>
You can of course do all sorts of combinations of this, but now you can do more specific and useful selections, such as:
cy.get('[data-cy="expenses"]').find('[data-cy="discounted"]').find('[data-cy="price"]').should(...)
And similar. This is flexible, because it reflects the structure of your data, and not the presentation, so you can change this to a list or whatever later. It avoids selecting of volatile things, so it's also more robust. It also uses a hierarchy rather than overly specific selectors.
The idea of adding things like data-cy-identifier allows you to do selections by ID (you can propagate it using javascript, angular, vue or whatever you use) and then checking things like the contents of a row with logically related items.
Hope it can get you going. Also I can recommend reading: https://docs.cypress.io/guides/references/best-practices.html
I'm using DataTables 1.10.15 and have the most basic table imaginable like
<table>
<thead>
<tr>
<th>Foo</th>
<th>Bar</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Foo</td>
<td>Bar</td>
</tr>
</tfoot>
<tbody>
</tbody>
</table>
On document.ready I access the footer nodes to add per-column-search callbacks; however .footer() on all column-objects only returns null and I have no idea why this is.
... table is the DT-object
table.columns().every(function() { console.log(this.footer()) })
... just prints a lot of null. .header() works without problems and table.table(0).footer() is in fact the footer node. Any idea?
You did not provide the full code but you need to have an instance of table
Working example : https://jsfiddle.net/jondion/ab2avuzk/
$(document).ready(function() {
var table = $('table').DataTable();
table.columns().every(function() {
console.log(this.footer()) // data...
})
});
jQuery 2.2.4
DataTables 1.10.15
Turns out that for some reason pulling the i18n file via ajax in the constructor causes .footer() to fail. Passing the literal values fixed the problem.
I need to render a table in which the user is allowed to edit some fields for each row, fields that will affect other fields in the same row.
For this reason I could not use bind-once on all the data I'm rendering.
If I got it right, simply using a code like the following
<table class="table table-bordered table-condensed table-hover">
<thead>
<tr class="info">
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="a in alist">
<td>{{::a.id}}</td>
<td>{{::a.cod}}</td>
<td>
<input
ng-model="a.sel"
type="checkbox"
class="input-sm"></input>
</td>
<td ng-if="a.sel">
{{::a.desc}}
</td>
<td ng-if="!a.sel">
"Other Content"
</td>
</tr>
</tbody>
will cause that for each time a user checks or uncheks the a.sel checkbox, all the angular {{vars}} in the page (not the {{::vars}}) will be watched for changes.
If this is true (and therefore that's the reason why page is slow when hundreds of rows are loaded) how could I tell angular I only want it to check if something has changed inside that specific row, that specific ng-repeat iteration?
Not sure how to proceed to get good performances, any other tips are appreciated.
Try using track by to tell angular what it should be evaluating on:
<tr ng-repeat="a in alist track by $index">
or
<tr ng-repeat="a in alist track by a.id">
more on that in the ng-repeat documentation
I have this HTML table:
<table id="languages" border="0" cellspacing="1">
<thead>
<tr>
<th>Language</th>
<th>Type</th>
<th>Invented</th>
</tr>
</thead>
<tbody>
<tr>
<td>Java</td>
<td>Static</td>
<td>1995</td>
</tr>
<tr>
<td>Ruby</td>
<td>Dynamic</td>
<td>1993</td>
</tr>
<tr>
<td>Smalltalk</td>
<td>Dynamic</td>
<td>1972</td>
</tr>
<tr>
<td>C++</td>
<td>Static</td>
<td>1983</td>
</tr>
</tbody>
</table>
When I run this JavaScript:
alert($('td').index($('td:contains(C++)')))
I get a pop up saying 9, which is what I would expect.
And when I run this: alert($('td:eq(9)').text()), the pop up says C++, again same as what one would expect. But if I try to put the first function/selection instead of hard coding 9 in the second selector, like this...
alert($('td:eq($('td').index($('td:contains(C++)')))').text())
// just replacing the hard coded 9 with the first selector, as it gives a value of 9
...nothing happens. I don't get any pop up saying C++, which is what one would expect, I don't get any pop up for that matter. Can anyone please tell me what am I doing wrong?
The problem is that you aren't escaping the single quotes in the inner selector, so you're effectively exiting the string at that point, which is throwing an error. Change this:
alert($('td:eq($('td').index($('td:contains(C++)')))').text())
To this:
alert($('td:eq(' + $('td').index($('td:contains(C++)')) + ')').text())
The below should work:
alert($('td:eq('+$('td').index($('td:contains(C++)'))+')').text())
I am using XForms to build a web application with XML-DB eXist-db as backend.
eXist transforms the XForms code into HTML and JavaScript.
First of all I got two instances:
<xf:instance xmlns="" id="results">
<result>
<ServiceDefinition>
<InventoryLabel LastChange="2012-01-24">SVC380712435</InventoryLabel>
<SystemName IPaddress="111.222.333.123">XXX</SystemName>
<Service ServiceCategory="Internetservice">Web-Server</Service>
<OSClass OperatingSystem="CentOS">UNIX</OSClass>
<SystemType Manufacturer="VMware">VM</SystemType>
<Backup/>
<Location SystemContact="Max Power" AdminGroup="power">N22</Location>
</ServiceDefinition>
....
</result>
</xf:instance>
<xf:instance xmlns="" id="domain">
<system name="XXX">
<NIC MAC="00-50-56-ae-00-3c"
time="1329167846" missed="1323350247" state="inactive"
IP="111.222.333.123" LAN="Test"/>
</system>
...
</xf:instance>
I want to build a table using xf:repeat to iterate through all the <ServiceDefinition> Elements in the 'results' instance. Every row contains a 'Status' column where I want to put the related 'state' information from the 'domain' instance.
This is the XForms code for the table:
<div class="table">
<table border="0">
<thead>
<tr>
<th class="sysName">Hostname</th>
<th class="services">Service</th>
<th class="os">OS Class</th>
<th class="location">Location</th>
<th class="link">Details</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<xf:repeat nodeset="instance('results')/result/ServiceDefinition" id="link-repeat">
<tr>
<td class="sysName"><xf:output ref="SystemName" /></td>
<td>
<xf:repeat nodeset="Service" class="row">
<div>
<xf:output ref="."/>
</div>
</xf:repeat>
</td>
<td class="os"><xf:output ref="OSClass"/> </td>
<td class="location"><xf:output ref="Location" /></td>
<td class="link">
<xf:trigger submission="view-entry" appearance="minimal" class="url">
<xf:label>View</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('URL-container')"
value="concat('serviceDetails.xql?svc=', instance('results')/result/ServiceDefinition[index('link-repeat')]/InventoryLabel)"/>
<xf:load ref="instance('URL-container')" />
</xf:action>
</xf:trigger>
</td>
<td>
<xf:output ref="instance('domain')/system[#name = instance('results')/result/ServiceDefinition[index('link-repeat')]/SystemName]/NIC/#state" />
</td>
</tr>
</xf:repeat>
</tbody>
</table>
</div>
The problem seems to be this part:
<td>
<xf:output ref="instance('domain')/system[#name = instance('results')/result/ServiceDefinition[index('link-repeat')]/SystemName]/NIC/#state" />
</td>
Is there something wrong with this expression? I want to get the state attribute of the system that matches the current node in the repeat statement.
However when I load the page and the 'results'-instance consist of many items I get a Javascript error:
A script on this page may be busy, or it may have stopped responding. You can stop the script now, or you can continue to see if the script will complete.
Script: http://test:8080/exist/xforms/xsltforms/xsltforms.js:771*
The line (in this case 771) always differs.
When the result instance is very small (up to about 20 Elements) it works as expected.
Any help or suggestion appreciated, I am new to all this, so please be patient.
Because XSLTForms has its own XPath engine written in JavaScript, browsers might be slow to evaluate expressions requiring to navigate through a lot of nodes, especially old versions of Internet Explorer.
Performance has been improved recently and you should try with latest build in SVN repository of XSLTForms at sourceforge.net.
Using the id() function is a possibility to heavily reduce evaluation time.
There is also an XSLTForms specific extension to indicate whether an instance contains only readonly data.
Did you try the Profiler (press F1 first) to have time measures?