ReactJS: Is it possible to change my 'data-target' attribute dynamically? rather then individually setting them? - reactjs

Basically I'm creating a bootstrap table in my react project and am using an accordion toggle to contain the excess info in a dropdown. As of now when i click the dropdown all of the dropdowns open, so i'm trying to set the data-target attribute (currently set to #demo1) and the id attribute to change dynamically in order to give me better control over which drop down is open and when.
I'm using React and bootstrap and am still fairly new :S
I tried setting data-target to a unique ID {item._id} which is the same as the key, but nothing happens i presume it's because i don't have the # in front of it, but it would error out if i add it to the front of the expression.
<tr
key={item._id}
className="accordion-toggle"
data-toggle="collapse"
data-target="#demo1"
>
{...}
</tr>
<tr>
<td colSpan="6" className="hiddenRow">
<div className="accordion-body collapse" id="demo1">
<table className="table table-dark">
</table>
</div>
</td>
</tr>

I would probably do this by tracking the state of all Dropdowns (open vs closed) in the parent component in an array, and passing it to the child component as a boolean prop such as 'isOpen'.
If there is more to it, perhaps you can attach a screenshot of what you are trying to do?

Related

How can I use ng-bind-html as an element?

For an Angular 1.2 project, I'd like to render a subset of <td>s inside of a table row using ng-bind-html in order to reduce the number of watchers. I cannot easily render all <td>s this way because some of them have ng-clicks, ng-if's and ng-classes attached to them.
Currently the ng-bind-html element is rendered as td children elements of the <td> that it's called in. However, ng-bind-html cannot be called as an element (must be an attribute).
Any ideas on how to approach this? (I've been looking at some jquery but I'm pretty new to that area).
<tr>
<td><span>{{entry.name}}</span></td>
<td ng-bind-html="generateStaticHtmlColumns(entry.data)"></td>
<td>{{entry.address | number}}</td>
<td ng-if='!entry.loading' tooltip position="bottom">{{entry.phone | number}}</td>
</tr>
Essentially, I'd like the <td> calling using ng-bind-html to be replaced with the "td"s it's returning rather than appending them as children.

Get first element in protractor

I want to verify the number of table rows in protractor, on a page in which tables of this type appear more than once. I've been trying to use the first-of-type selector, but it seems to be catching both tables because they do not appear side by side.
For example, given this HTML:
<div>
<table class="foo">
<tr>
<th>First row</th>
<th>Second row</th>
<th>Third row</th>
<th>Fourth row</th>
</tr>
</table>
</div>
<div>
<table class="foo">
<tr>
<th>First row</th>
<th>Second row</th>
<th>Third row</th>
<th>Fourth row</th>
</tr>
</table>
</div>
And this protractor code:
element.all(by.css('table:first-of-type tr:first-of-type th')).then(function (elements) {
expect(elements.length).toBe(4);
});
Protractor is failing on the grounds that there are 8 elements and not 4. It seems the table:first-of-type selector is catching both elements, since they're both the first children of their parent div components. My project is structured in such a way that it's better not to add individual classes to each wrapping div.
Is there a way to get the first element found in Protractor and then search its child elements?
I have not used :first-of-type as a css selector in Protractor; however, you could get the first table with all th's and then check to see if the count is 4.
expect(element.all(by.css('table')).first().all(by.css('th')).count()).toBe(4);
You can certainly do it the way #cnishina suggested (and I would actually prefer his approach over making a long CSS selector), but if you want to continue using a single CSS selector for this problem, you should also apply the first-of-type (or first-child) to the parent div:
div:first-of-type > table:first-of-type > tr:first-of-type > th
I've also added the > to enforce the direct parent-child relationships.

Change display text based upon value

I am displaying Errors on my Html page using Angular JS. The problem is I am receiving only error codes from the HTML . What are the various ways in which i can change the error code to the the Error text i like
<table>
<tr ng-repeat='item in errorsd'>
<td align="left" class="validationMsg"> {{item.message}}</td></tr>
</table>
If my item.message has one . I would like to display Beginner ,if its 2 Intermediate like that and so on . Should i use ng-if ? should i use ng-switch or should i input some logic on the controller side .
Should i use ng-if ?
ng-switch is more readable and hence a better option. Later when you look back at the code it will be intuitive to you and other developers about what this code does.
should i input some logic on the controller side .
Why put a logic in controller-side if the framework already provides a solution for such use-case?
I would do it like:
<table>
<tr ng-repeat='item in errorsd'>
<td ng-switch="item.message" align="left" class="validationMsg">
<span ng-switch-when="1">Beginner</span>
<span ng-switch-when="2">Intermediate</span>
<!-- and so on.. -->
</td>
</tr>
</table>
I say use a switch statement inside of your controller.
So depending on the value, the global message would change thus displaying the correct one when triggering the validation msg box to show.

Angular JS Nested ng-repeat for bootstrap badges

Im trying to tag different video items in a bootstrap table. I'm already using an ng-repeat to loop over the array of objects which store video data. I'm now trying to create a nested ng-repeat to loop over another array of "tags" within the ng-repeat that creates each table row.
I'm getting some weird results though. I was hoping that I could just put an ng-repeat on the td and then put the angular expression in a span with the boostrap class "badge". Any thoughts as to whats going wrong?
http://jsfiddle.net/jheimpel/6nh100ca/
<tr ng-repeat="topic in topics">
<td><a ng-href="#/{{topic.url}}"><i class="fa fa-play"></i></a></td>
<td>{{topic.topic}}</td>
<td>{{topic.date}}</td>
<td>{{topic.presenter}}</td>
<td ng-repeat="tag in topic.tags">
<span class="badge">{{topic.tags}}</span>
</td>
</tr>
Change it to
<span class="badge" ng-bind="tag"></span>
You're telling it to print out the array you're ng-repeating instead of the object the ng-repeat is giving you. Also ng-bind is better, see this

Unable to click this ExtJS button using Selenium WebDriver

<td id="ext-gen383" class="x-toolbar-cell">
<table id="ext-comp-1144" class="x-btn x-btn-icon" cellspacing="0">
<tbody class="x-btn-small x-btn-icon-small-left">
<tr>
<tr>
<td class="x-btn-ml">
<td class="x-btn-mc">
<em class=" x-unselectable" unselectable="on">
**<button id="ext-gen384" class="x-btn-text x-tbar-page-last" type="button">** </button>
</em>
I tried to click the button. Please see the html above. Tried so many ways.
eg:
//*[contains(#class,'x-btn-text x-tbar-page-last')] or
//button[contains(#class,'x-btn-text x-tbar-page-last')]
But still not working.
I'm guessing that only the number at the end is generated. Try:
By.cssSelector("em.x-unselectable > button[id^='ext-gen']")
Also, looking at that <em>, are you sure that that class isn't making the button NOT clickable? By the name, it looks like it disables clicks.
Its hard to tell without seeing the full html of the page. Since ExtJS generates random ids, there really are not any good properties to use for finding the element.
I would recommend just using an XPath, and then use an index (if your page has multiple button elements):
//button[1]
And adjust the index accordingly until you get the correct button to click.
Likewise, you could use the WebDriver API for driver.findElements, which will return a collection of all matching items, and then you could apply the index to that collection to get the correct button.

Resources