16

I'm trying to display a table with links and mailto's in a display template using Knockout. I'm still really new to knock out to I apologize in advance!

This is what my display template was originally:

<script type="text/template" id="customerSearchDisplayTemplate">
    <td class="hiddenId">{0}</td>
    <td><a href="/wrenchsciencewebadmin2/UserManager/Customer/CustomerEditor.aspx?CustomerID={1}">{1}</a></td>
    <td><a href="mailto:{2}">{2}</a></td>
    <td>{3}</td>
    <td>{4}</td>
    <td>{5}</td>
    <td>{6}</td>     
    <td>{7}</td>
    <td><a href="/wrenchsciencewebadmin2/Common/PopupWindows/CustomerNotes.aspx?customerid={8}">{8}</a></td>                     
</script>

and this is what I have so far, minus the mailto AND links:

<script type="text/template" id="customerSearchDisplayTemplate">
    <tr>
        <td class = "hiddenId"><span data-bind="text: customerSearchID"/></td> 
        <td><span data-bind="text: fullName" /></td>
        <td><span data-bind="text: primaryEmail" /></td>
        <td><span data-bind="text: secondaryEmail" /></td>
        <td><span data-bind="text: homePhone" /></td>
        <td><span data-bind="text: workPhone" /></td>
        <td><span data-bind="text: mobilePhone" /></td>
        <td><span data-bind="text: lastLogonDate" /></td>
        <td><span data-bind="text: wsNotes" /></td>            
    </tr>
</script>
Bobandra
  • 161
  • 1
  • 1
  • 7

3 Answers3

24

Using the attr and text properties in the data-bind attribute like so:

<script type="text/template" id="customerSearchDisplayTemplate">
    <tr>
        <td class = "hiddenId"><span data-bind="text: customerSearchID"/></td> 
        <td><span data-bind="text: fullName" /></td>
        <td>
            <span>
                <a data-bind="text: primaryEmail, 
                              attr: {href: 'mailto:'+primaryEmail()}" />
            <span/>
        </td>
        <td>
            <span>
                <a data-bind="text: secondaryEmail, 
                              attr: {href: 'mailto:'+secondaryEmail()}" />
            <span/>
        </td>
        <td><span data-bind="text: homePhone" /></td>
        <td><span data-bind="text: workPhone" /></td>
        <td><span data-bind="text: mobilePhone" /></td>
        <td><span data-bind="text: lastLogonDate" /></td>
        <td><span data-bind="text: wsNotes" /></td>            
    </tr>
</script>
Kris
  • 40,604
  • 9
  • 72
  • 101
4

Be sure to access the emails via the function syntax when binding the attr i.e. primaryEmail() otherwise it will return the function definitions rather than the value.

<div data-bind="template: { name : 'customerSearchDisplayTemplate'}"></div>

<script type="text/template" id="customerSearchDisplayTemplate">
    <tr>
        <td class="hiddenId">
            <span data-bind="text: customerSearchID"/>
        </td> 
        <td><span data-bind="text: fullName" /></td>
        <td>
            <a data-bind="text: primaryEmail, 
                          attr: { href : 'mailto:'+primaryEmail() }" />
        </td>
        <td>
            <a data-bind="text: secondaryEmail, 
                          attr: { href : 'mailto:'+secondaryEmail() }"/>
        </td>
        <td><span data-bind="text: homePhone" /></td>
        <td><span data-bind="text: workPhone" /></td>
        <td><span data-bind="text: mobilePhone" /></td>
        <td><span data-bind="text: lastLogonDate" /></td>
        <td><span data-bind="text: wsNotes" /></td>            
    </tr>
</script>

Example: http://jsfiddle.net/lifetimelearner/yr7SP/2/

3

If you want to go MVVM all the way, it's best to keep your View as dumb as possible:

<a data-bind="text: primaryEmail, attr: {href: primaryEmailMailtoLink}"></a>

Then make a computed observable on your view model:

var ViewModel = function() {
    var self = this;

    // Observable property:
    self.primaryEmail = ko.observable('foo@bar.com');

    // Dependent observable:
    self.primaryEmailMailtoLink = ko.computed(function() {
            return 'mailto: ' + self.primaryEmail();
    };

    // Etc. (rest of your view model)
}
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • 3
    I disagree that this is "MVVM all the way." MVVM doesn't mean stupid views, it means *separated* views and viewmodels. This is actually tying the viewmodel to the view by brining in HTML link knowledge. The fact that the email address is going to be used by a link is knowledge the viewmodel shouldn't have, but which the view *should* have. You could make a `binding handler` for the `mailto` link, but I think that's unncesarry. The view displaying an email in a `mailto` link is view behavior, and should be left there. – Kyeotic Aug 20 '13 at 21:52
  • @Tyrsius You make a valid point. However, I still think the "mailto" is *not* an aspect of the *View*, but an aspect of your *Model* as it encapsulates business logic. Consider the situation where you want to add a CC or use another advanced [mailto feature](http://en.wikipedia.org/wiki/Mailto). If you have the logic in your *Model* it'll be easy to change, only in *one* place: the computed observable. If you've done the string concatenation in your view you'll have to update every single place you've used a mailto link. – Jeroen Aug 20 '13 at 22:23
  • Regardless of taste, the code's a valid way to solve the OP's problem, by the way ;-) – Jeroen Aug 20 '13 at 22:27
  • I never said it was invalid... just that I disagreed with your statement. You make a good point about `mailto` having features though, and I think a `binding handler` would be an appropriate way to include those, by passing options to it. I still don't think that its business logic. The person you are mailing has an `emailaddress`, but the person doesn't have a `mailto` link; it's not a property of the model, and it isn't a function either. It's purely a way to show the email address as a link that can be clicked on. – Kyeotic Aug 20 '13 at 22:40
  • @Tyrsius Apologies, the "validness" comment wasn't aimed specifically at you, just at whoever clicked the "*This answer is not useful*" button. – Jeroen Aug 20 '13 at 22:42