Ember link-to on table row issue - javascript

I am trying to use a link-to around a whole table row. Here is how I am setting it up:
{{#each model as |servicerequest|}}
{{#link-to 'servicerequest.detail' servicerequestId tagName="tr"}}
<td>
{{servicerequest.status}}
</td>
<td>
<strong>{{servicerequest.srdescription}}</strong>
</td>
<td>
{{servicerequest.priority}}
</td>
{{/link-to}}
{{/each}}
I see the data but it is not a clickable link, just text. Any ideas on what I am doing wrong?

Consider using divs with flexbox and proper styling. Tables are not the best option and are a quite ancient solution already.
Some examples:
https://hashnode.com/post/really-responsive-tables-using-css3-flexbox-cijzbxd8n00pwvm53sl4l42cx

The link-to will not generate a href attribute if you use any tagName other than a. See changes in 1.4.0.
So maybe try putting the link-to helper around the tags.

Related

How to identify xpath of an element which do not have any attribute information

I want to identify an element which is a text "My Portal" from td tag. Below is my HTML
<tbody>
<tr>
<td>
<!-- rendered always true, custom column names are also label -->
My Portal
<!-- rendered always false, this feature is not required -->
</td>
</tr>
</tbody>
I have tried below xpaths as shown below, but none of them works:
1. .//td[text()="My Portal"]
2. .//td[contains(text(),"My Portal")]
After some search in the internet I found normalize-space() method which will remove the trailing and unnecessary white spaces. I have tried the method using the below xpath
.//td[normalize-space()="My Portal"]
Am able to identify the element, but in the firebug it is showing as 2 matching nodes. Please find the attachment for the highlighted elements in the firebug
My questions are:
Why two tags are getting highlighted?
Why .//td[contains(text(),"My Portal")] does not work?
How to identify the "My Portal" uniquely?
Can anyone please help?
There are several solutions. An efficient approach is to specify the exact path from the root node to the td you want. Something like
/html/body/table/tbody/tr/td/table/tbody/tr/td[normalize-space()='My Portal']
If you know that there are no more than two nesting tables, you can shorten this to
//td//td[normalize-space()='My Portal']
If you want the td in the innermost table regardless of table structure, try
//td[not(.//table) and normalize-space()='My Portal']
This isn't very efficient though. If you know that the text "My Portal" appears in an immediate text child of td, try
//td[text()[normalize-space()='My Portal']]
To uniquely identify the second td, what you have to do is add an additional filter. So if you look at the difference between the 2 tags highlighted, the parent has a class and the child doesn't. So if you need the second td, the xpath would be //td[normalize-space()='My Portal' and not(#class='rich-table-cell')]
If you need the parent then: //td[normalize-space()='My Portal' and #class='rich-table-cell']
Instead of using text() try .
.//td[contains(.,"My Portal")]
To Answer your questions:
1- Because you are using a global selector, "//", with this selector XPAth will find all the elements into the tree, so if you want select only one td you should specific the path, something like this
/table/tbody/table/td[contains(text(),"My Portal")]
2- The command that you are using it should work, I already tried, check your path again, maybe you are not selecting his parent or you are starting from the wrong path.
function xpath(){
var input = document.getElementById("xpath").value
var cell = document.evaluate( input, document, null, XPathResult.ANY_TYPE, null );
var cellvalue = cell.iterateNext();
console.log(cellvalue);
alert(cellvalue.data);
};
<html>
<head>
</head>
<body>
<input type="text" id="xpath" value='//body/table/tbody/tr/td/table//td[contains(text(),"My Value")]/text()'/> <input type="button" onclick="xpath()" value="Execute"/>
<table>
<tbody>
<tr>
<td>
<table>
<tbody>
<tr>
<td>
My Value
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>

Defining an ID for html element in Emberjs/handlebars fails

I have following issue here:
<ul class="aClass">
{{#if something}}
<li>{{#link-to "blub" bind-attr data-testid=aID}}{{loc "blub"}}{{/link-to}}</li>
{{/if}}
</ul>
so i want to have an element(the link-to is rendered to ...) in the resulting element with the id aId. But the element does not contain the wanted id in the rendered HTML. something like this:
...
any ideas?
In Ember, bind-attr shouldn't be used inside of your link-to help as that should only be used inside of html elements:
<a {{bind-attr href=myLink}}>My Link</a>
Inside of Handlebars helpers, you just define the property directly.
{{#link-to "blub" data-testID="aID"}}{{loc "blub"}}{{/link-to}}
The attribute is not rendered into the HTML if the quotes are missing.
But you also need to reopen the LinkView:
Ember.LinkView.reopen({
attributeBindings: ['data-testID']
});
See similar question here.
And the Ember docs here.
Try using quotes:
{{#link-to "blub" bind-attr data-testid="aID"}}{{loc "blub"}}{{/link-to}}
A lack of quotes will cause Ember to try a property lookup on the current view context, instead of just spitting out a string as you'd like it to.

Handlebars does not fill table

I am using Handlebars (v 1.0.0) to fill a table in HTML.
However somehow it does not fill the table like I am used to.
Here is my template:
{{#if users}}
<table>
{{#each users}}
<tr>
<td>{{username}}</td>
<td>{{email}}</td>
</tr>
{{/each}}
</table>
{{else}}
<h3>No users found!</h3>
{{/if}}
So I does find users because I do not see the "No users found!" and when I call an empty object it does show the "No users found!".
When I do not use the table and print out these users like the next example. The usersnames and mail address' will show up in my HTML.
{{#if users}}
{{#each users}}
{{username}}<br/>
{{email}}<br/>
{{/each}}
{{else}}
<h3>No users found!</h3>
{{/if}}
Here is how my template is build in the javascript:
var htmlSource = $(data).html();
var template = Handlebars.compile(htmlSource);
var compiled = template(usersArray);
that.$el.html(compiled);
Now when I console.log the compiled object, it doesn't show the table already.
Do you know why it doesn't work and can you help me out?
EDIT:
I just tested some more and found that the data will show up in the HTML when I leave out the <table> tags. However the <tr> and <td> won't show up in html. The data in it will be shown.
EDIT 2:
I found out that it seems to be a jquery issue or javascript issue.
When I console.log the htmlSource the HTML template is changed to this:
{{#if users}}
{{#each users}}
{{/each}}
{{else}}
<h3>No users found!</h3>
{{/if}}
<table><tr>
<td>{{username}}</td>
<td>{{email}}</td>
</tr></table>
As you can see the table is moved outside the if statement.
I tried other jquery versions (2.0.2, 2.0.3, 2.0.1, 1.10.2) but this didn't work.
I tried using the innerXHTML script however this works the same as jQuery.
So my guess is that it might be a FireFox issue (though I tried 25 and 26), Chrome does the same... maybe something in EcmaScript??
I will let you know soon...
EDIT 3:
I created an html file with the html I need. With a script I get the specific section of html I need and place this in the data variable.
Now when console logging the data (console.log(data)) there is nothing wrong.
When console logging the data with jQuery, the html is altered: console.log($(data));
It seems something is going wrong there.. but only when using table tags.
Is this something jQuery can't handle? I don't know. I know how to overcome this issue by using the script tag... Though I would like to load that using require ;)
P.S. nemesv thanks for you're edits ;)
Make sure you're outputting your template in a tag so the browser don't try to parse it.
<script type="x-template" id="the-tpl">
{{#if users}}
<table>
{{#each users}}
<tr>
<td>{{username}}</td>
<td>{{email}}</td>
</tr>
{{/each}}
</table>
{{else}}
<h3>No users found!</h3>
{{/if}}
</script>
If there's no type attribute on the script tag, the HTML parser will find a bug and try to resolve it. From your bug details, it really looks like it is the case here.
Using require
As you noted you load using Require, than make sure you load your template using the text! plugin: require("text!path/to/template.html")
To be even fancier, you could delegate all the handlebars compilation to a handlebars template loading plugin so templates are precompiled inside your build - this is probably the best.
Either way, your issue is that your template get parsed by the HTML parser and that is breaking your template content. Make sure you load it as "text" via XMLHttpRequest or with require or inside a script tag correctly typed.
Simon's solution is the right one and problem is discussed in various comments.
I am just putting the pieces here.
as #rescuecreative pointed out some browsers remove empty <table> tags when the html is inserted in DOM.
The case here is a bit similar. The browsers do misbehave when they see invalid markup. but in this case its not because of missing tr, td inside table. its because of extra lines before tr in the table.
Your problem starts here.
var htmlSource = $(data).html();
whatever loading mechanism you are using, you inserting the template in the DOM before compiling it with handlebars.
This is what happens when you add uncompiled template to DOM.
{{#if users}} <!-- browser does not understand this and tries to print it as it is-->
<table> <!-- browser sees the table tag and immediately looks for child TR, tbody, thead -->
{{#each users}} <!-- but instead finds plain text and hence considers it as invalid markup -->
<tr> <!-- the same story is repeated again>
<td>{{username}}</td>
<td>{{email}}</td>
</tr>
{{/each}} <!-- such plain strings are taken out of table markup and placed before or after depending upon the browser, in case of chrome placed before the table -->
</table>
{{else}}
<h3>No users found!</h3>
{{/if}}
This is how chrome renders it -
{{#if users}}
{{#each users}}
{{/each}}
<table>
<tbody>
<tr>
<td>{{username}}</td>
<td>{{email}}</td>
</tr>
</tbody>
</table>
{{else}}
<h3>No users found!</h3>
{{/if}}
I dont have firefox with me as of now. but i am sure firefox has its own markup correction method.
after this when you take it out of DOM using jquery and compile
var htmlSource = $(data).html();
var template = Handlebars.compile(htmlSource);
it will just output this
<table>
<tbody>
<tr>
<td>{{username}}</td>
<td>{{email}}</td>
</tr>
</tbody>
</table>
if you want you can dump it after compilation to see.
var compiled = template(usersArray);
console.log(compiled);
that.$el.html(compiled);
This also explains why you are getting username and email when you strip out table markup in the original template.
Now to solve this issue either use text plugin as Simon pointed out. or place the template inline.
I too use requriejs with something along the following
define([
'underscore', // you can replace this with handlebars
'text!path/to/template.html'
], function(_, Tmpl){
return _.template(Tmpl); //and handlebar pre-compilation here
});
this way you can also replace this module with a pre-compiled template in your build process.

Ember.js - Ember.Js View inside handlebars conditional: view not being displayed?

I've got a handlebars conditional statement in a table, and inside that I have a view.
If i remove the conditional then the view template is displayed. If I remove the view template, the straight html is displayed. But if both are there, the view template is never shown, and there is no error shown in the console:
<script type="text/x-handlebars" data-template-name="application">
<table>
<tr>
<td>
<button {{action 'click_me'}}>Click me</button>
</td>
</tr>
{{#if controller.new_visible}}
{{#view App.MyView}}
<tr>
<td>
Hello!
</td>
</tr>
{{/view}}
{{/if}}
</table>
</script>
What am I doing wrong?
Further to this, it would seem (from http://emberjs.com/guides/understanding-ember/the-view-layer/, section 4) that Ember creates virtual views for Handlebars logic block helpers (like {{#if}}, {{#unless}}, and so on. They're not part of the regular view hierarchy, so they don't play nicely with regular nested child views.
I suspect the answer to this is to be found somewhere in this line:
"When the path passed to an {{#if}} or {{#with}} changes, Ember automatically re-renders the virtual view, which will replace its contents, and importantly, destroy all child views to free up their memory." (from the section linked above).
My best guess is that the {{#if}} block is re-rendering on insert, which destroys the 'child' {{#view}} block within it.
move your condition inside view. see this jsFiddle
{{#view App.MyView}}
{{#if controller.new_visible}}
<tr>
<td>
Hello!
</td>
</tr>
{{/if}}
{{/view}}

AngularJS - Directives with Angular UI Bootstrap

I'm using Angular UI - Bootstrap, specifically the Typeahead directive. http://angular-ui.github.io/bootstrap/#/typeahead
I'm attempting to use the 'typeahead-template-url' to create custom html templates for my suggestion boxes. After trying multiple techniques, unsuccessfully, I discovered that by purposely messing up my quotation marks 'solved' the display issues. I would love to understand why this is breaking and get it working properly.
For example: this works
<table class="> <!--see class quote error -->
<tr>
<td>
<div ng-mouseenter="selectActive($index)" ng-click="selectMatch($index)">
<a>ID{{ match.model.id }} - {{ match.model.text }}</a>
</div>
</td>
</tr>
</table>
This DOESN'T WORK
<table class="">
<tr>
<td>
<div ng-mouseenter="selectActive($index)" ng-click="selectMatch($index)">
<a>ID{{ match.model.id }} - {{ match.model.text }}</a>
</div>
</td>
</tr>
</table>
FIDDLE is here: http://jsfiddle.net/nicktest222/JXtaZ/24/
Additionally, when you select an item in the results list, it returns the entire object. How can I get it to return a specific property in the object?
Any help would be greatly appreciated.
Thanks
I think it is the way you add your template (columnTwo.html) in JSFiddle.
Look at my demo (which is based on yours): http://jsbin.com/aMOrOra/1/edit?html,js,output
As for the typeahead property:
<input type="text" ng-model="monkey" typeahead-template-url="columnTwo.html" typeahead="suggestion as suggestion.text for suggestion in sample_data | filter: $viewValue" />
Here it means that the suggestion object is used as the selected value, but I want to display only the suggestion.text property in the box. But monkey will still be set to the selected suggestion object.
Just so you know, your current filter will look for the query on every properties of the suggestion object, not only text.
EDIT: To filter only the text property, use the filter like this:
filter:{'text':$viewValue}

Categories