ng-repeat elements over nested objects - html

Say I have a nested object literal, and I want to display its contents in a table.
If the object is 2 levels deep, I can use:
<table>
<thead>
<tr>
<td>key</td>
<td>value</td>
</tr>
</thead>
<tbody ng-repeat="(key01, value01) in data">
<tr ng-repeat="(key02, value02) in value01">
<td>{{key02}}</td>
<td>{{value02}}</td>
</tr>
</tbody>
</table>
If I have a nested object that is 3 or 4 levels deep, using a similar method how would I display the data in a table? The best I have is from this previously answered question, however I do not want conduct this logic in a controller, as suggested here.
I need a way to nest more than 2 ng-Repeats as seen above since in my application, the key names are variable at data generation.
An example of a 3 level deep nest object:
$scope.someVar = { 'data': {
'A': {
'x':'someValue'
},
'B': {
'y':'anotherValue'
}
}
}

Unfortunately for your stated requirements it's not possible. The table element structure just doesn't have the kind of nesting you want. I know you said you don't want to do this in a controller but that's probably the best way of doing this as a table is a way of representing 2D information, not more.
Also it should be said that if you're putting a lot of data in these nested ngRepeats you're very likely to slow the browser down to an unusable state.
If you really can't do some kind of transformation in the controller (which is easier on the browser as it's done once, instead of every time something changes...) you would have to use div's with table like styling. Try here (link)

u should be doing something like this
$scope.someVar = { 'data': {
'A': {
'x':'someValue'
},
'B': {
'y':'anotherValue'
}
}
then you have to use ng-repeat like this,
<tbody ng-repeat="(key01, value01) in someVar.data">
<tr ng-repeat="(key02, value02) in value01">

Related

Adding Substring in table loop in Html.DisplayFor

Im just asking how to implement Substring code in Razor Html DisplayFor
Actually It was working before then I added the Substring to get the first 5 number in the table then I encountered an error
An exception of type 'System.InvalidOperationException' occurred in System.Web.Mvc.dll but was not handled in user code
Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Here are my set of Codes:
<tbody>
#for (var i = 0; i < Model.Cards.Count; ++i)
{
var counter = i + 1;
<tr>
<td valign="middle">
<p class="small">#counter</p>
</td>
<td valign="middle">
<p class="small">#Html.DisplayFor(x => x.Cards[i].Number.Substring(0,5))</p>
</td>
</tr>
}
</tbody>
Thanks in Advance !
As Stephen said in comments, using .Substring in the middle of your view doesn't really make sens.
Instead, in your ViewModel (the one which defines your Number property), add the following property :
public string DisplayableNumber => Number.Length > 5 ? Number.ToString().Substring(0, 5) : "WhatYouWantHere";
This will work for C# 5+, else you can use the old way and initialize it in the default constructor.
Then, use it in your view :
#Html.DisplayFor(x => x.Cards[i].DisplayableNumber)
Plus, this is good practice to use this type of property in ViewModel, as Views should't handle any logic.

Datatables: Pass additional/hidden row information through JSON

Short
Can I pass additional data through JSON objects to Datatables which won't be rendered by Datatables?
Longer description
I'm having issues with Internet Explorer (sigh) rendering Datatables in a frustratingly slow manor. Having scoured the web for solutions the best bet I've figured is that I should transfer the creation of the table from HTML to JSON.
Our HTML rows currently look like this:
<tr their_ID="{$data[$i]['their_ID']}" class="$no_select $exists">
<td>$ii.</td>
<td surname>{$data[$i]['surname']}</td>
<td forename>{$data[$i]['forename']}</td>
<td title>{$data[$i]['title']}</td>
<td gender>{$data[$i]['gender']}</td>
<td email>{$data[$i]['email']}</td>
<td import class="centerText"><input type="checkbox" $checked ourID="$ourID" /></td>
</tr>
The JSON seems great if all you are passing is raw data. But for the rest of the functionality to work we need all the additional data for each row and table cell to be passed.
If I have the following:
{
"DT_RowId": "1234",
"ii": "$ii",
"surname": "Surname",
"forename": "Forename",
"title": "Title",
"gender": "M",
"email": "abc#xyz.com",
"import": "$ourID"
},
Using the createdRow callback I can set most of the row and cell data using JS. The ID could be taken and renamed to the custom attribute their_ID. The keynames could be used to add the custom attributes to the cells. I could convert the import cell into a checkbox using JS etc. Determining whether the row could be selected or not ($no_select) could also be done with JS.
The problem we're left with is:
How do we pass the server side determined data of whether the user exists in our database or not?
Is it possible to pass additional data through the JSON which won't be rendered by the Datatables but will be available for us to use? $exists and $checked (which really could be a single variable as far as the JS is concerned)
E.g. theoretically:
{
"DT_RowId": "1234",
"ii": "$ii",
"surname": "Surname",
"forename": "Forename",
"title": "Title",
"gender": "M",
"email": "abc#xyz.com",
"import": $ourID,
"hiddenClientSideData": {
"exists": 1|0,
"checked": 1|0
}
},
Thanks for any help, and if you need any clarifications please ask.
You should be able to use the ColumnDefs and set the visible property to false. Create a column for that data. And then target that column and make it invisible
https://datatables.net/reference/option/columnDefs
You would create two additional th and two addadditional td cells in your table definition. Then just send the data as you are with other properties. To begin with render it on the UI to make sure it is all sending correctly. Then use the columnDefs to target and hide those last two columns. You will still be able to use datatables api to get the data to act on it if needed

Concordion - how can i set a value into a table?

At some stage in a concordion test I have, I set a value to some random number.
This value is passed along, and later on , I have some output. The output is "checked" using the concordion "table" setup, where i compare an output value to what I expect it to be.
The problem I have is that I would like to check against the random number mentioned above. When I get the random number, I can set it to something Concordion can store -
<span c:set="#prefixValue">Bob</span>
Well, you get the idea - I replace "Bob" with a getter for my value.
But when I try to use it:
<table c:execute="#actual = getValue(#report, #xpath)">
<tr>
<th>Field name</th>
<th c:assertEquals="#actual">Value</th>
<th c:set="#xpath">Xpath</th>
</tr>
<tr>
<td>UnrelatedValue</td>
<td>SomeDeterminateValue</td>
<td>theXpathForThisToCompareTo</td>
</tr>
<tr>
<td>prefix</td>
<td><span c:echo="#prefixValue" /></td>
<td>differentXpathForThisToCompareTo</td>
</tr>
The whole shebang grinds to a halt, complaining that
"
Commands must be placed on elements when using 'execute' or 'verifyRows' commands on a <table>.
"
How can I use a pre-determined value in a table in Concordion?
The specs aren't supposed to have random elements in them. They're supposed to contain a specific example or set of examples. Rather than using a random number, hardcode a particular value and then you can use it later on.
To tell the fixture about the hardcoded value you can do this:
<span c:execute="setPrefixValue(#TEXT)">Bob</span>
Then in the fixture:
public void setPrefixValue(String prefixValue) {
// TODO: Whatever system configuration you need to do
}
If it isn't actually possible to set the value in your system under test, then use your fixture code to map between the hardcoded value and the actual random value.
public String getValue(String report, String xpath) {
String value = report(report).get(xpath);
if (value.equals(knownRandomValue)) {
return hardcodedValue;
}
return value;
}
Oh Lord! I didn't realise Concordion was going to get all rigid on me.
To fix, I had to alter the Concordion method I was using to be less stupidly rigid.
Following the general ideas here:
http://automatingsoftwaretesting.wordpress.com/2011/05/27/write-your-own-concordion-command-an-example-for-asserting/
I wrote this:
#Override
public void verify(CommandCall commandCall, Evaluator evaluator, ResultRecorder resultRecorder) {
Object expected = evaluator.evaluate(commandCall.getChildren().get(0).getExpression());
Object actual = evaluator.evaluate(commandCall.getExpression());
Element element = setupTheGoshDarnElement(commandCall, expected);
if (actual.equals(expected)) {
resultRecorder.record(Result.SUCCESS);
announceSuccess(element);
} else {
resultRecorder.record(Result.FAILURE);
announceFailure(element, expected.toString(), actual);
}
}
private Element setupTheGoshDarnElement(CommandCall commandCall, Object expected) {
Element e = commandCall.getElement();
e.appendText(expected.toString());
return e;
}
private void announceFailure(Element element, String expected, Object actual) {
listeners.announce().failureReported(new AssertFailureEvent(element, expected, actual));
}
private void announceSuccess(Element element) {
listeners.announce().successReported(new AssertSuccessEvent(element));
}
And so made a new "evaluator" ~ the rest of the evaluator is identical to the AssertEqualsCommand, if you're wondering.
This neatly checks the element and evaluates. Why concordion didn't do this ~ it isn't rocket science at all ~ is beyond me!
NOTE that I still need to use the "expanded table" in my question to get this to work, the short-form table has it's own issues with evaluating inner expressions.

Verifying HTML table data in WebDriver

Can anyone plz explain me how to verify the data in HTML table using WebDriver?
HTML is like below..I need to verify the values xyz, abcd, 1234, 5678 on the webpage
<table>
<tr>
<td>xyz</td>
<td>abcd</td>
</tr>
<tr>
<td>1234</td>
<td>5678</td>
</tr>
</table>
Thanks in Advance!!
mra.
Keeping in mind your excerpt from the question:
I need to verify the values xyz, abcd, 1234, 5678 on the webpage
I suggest you try to identify these values using locators and then asserting/verifying the same.
In this example I have used XPath ( a bit verbose for clarity)as the locating strategy.Hope this helps.
try {
assertEquals("xyz", driver.findElement(By.xpath("//table//tr[1]/td[1]")).getText());
} catch (Error e) {
verificationErrors.append(e.toString());
}
try {
assertEquals("abcd", driver.findElement(By.xpath("//table//tr[1]/td[2]")).getText());
} catch (Error e) {
verificationErrors.append(e.toString());
}
try {
assertEquals("1234", driver.findElement(By.xpath("//table//tr[2]/td[1]")).getText());
} catch (Error e) {
verificationErrors.append(e.toString());
}
try {
assertEquals("5678", driver.findElement(By.xpath("//table//tr[2]/td[2]")).getText());
} catch (Error e) {
verificationErrors.append(e.toString());
}
Your approach will depend on whether that table will only ever contain 2 rows and 2 columns. Will the rows and columns always exist in the same order? If not then the xcode example provider before will work, if not you might need to be a bit more creative.
One approach that I've used before to crawl through a table is similar to this.
Define a WebElement that represents your table.
WebElement yourTable = driver.findElement(By.tagname("table"));
Next create a List of WebElements that represent each row in the table.
List<WebElement> tableRows = yourTable.findElements(By.tagname("tr");
Finally, you can loop through the rows of the table until you find the data you are looking for.
for(int i=0; i<tableRows.size(); i++){
WebElement row = tableRows.get(i);
now do whatever you want with your WebElement that represents a single row of the table;
}
Hope this helps.

Some HTML/CSS to get around a drawback in Struts2

I am trying to get an HTML page like: http://jsbin.com/awoco.
This is a JSP page so it will include scriptlets. Final HTML output will be kind of like this (tags unclosed to save space):
<%
Iterator it = MyList.iterator()
While (it.hasNext())
SomeClass all = it.next();
SomeClass a = it.next();
SomeClass b = it.next();
%>
<tr>
<td rowspan=3 valign=top>Red<td><%=all.Name()%><td><%=all.price()%><td><%=all.originalPrice()%>
</tr>
<tr>
<td><%=a.Name()%><td><%=a.price()%><td><%=a.originalPrice()%>
</tr>
<tr >
<td><%=b.Name()%><td><%=b.price()%><td><%=b.originalPrice()%>
</tr>
As you can see, I have to call next() 3 times inside the while loop. This is because the source of the data is a List populated that way, and I have to show the data in the exact same manner as in the link provided above.
Is there a way to change the HTML output somehow so that I don't have to call next() more than once, but still get the same table structure?
Change your data structures. MyList should be list of (something like) AgregateClass which will contain 3 members of type SomeClass (all,a,b) and then simply iterate through MyList.
Just few tips:
If you are using Struts2 you can use <s:iterator> tag to iterate through collections. documentation
Since JSP 2.0 or so you can write ${b.price} instead of <%=b.price()%>
You should change tags you added to your question as it has nothing to do with html or css.