1

I have an ASP.NET Web API method that returns a list of products:

public async Task<IEnumerable<Product>> Get()
{
    var products = new IEnumerable<Product>();
    // Data populated here
    return products;
}

This API call is used by a Knockout.js observableArray:

// Define viewmodel
var myViewModel = {
    products = ko.observableArray([]);
};

// Apply knockout bindings
ko.applyBindings(vm);

// Function that obtains product data
function listProducts(viewmodel) {
    var productsQuery = "api/products/get";

    // Send an AJAX request
    $.getJSON(productsQuery).done(viewmodel.products);
}

I would like to apply a click binding to these products, which would be a method named myClickFunction in this case. If possible, the method should be a function belonging to the objects that are returned by my Web API call :

<ul data-bind="foreach: products">
    <li class="item" data-bind="text: productName, click: myClickFunction">
    </li>
</ul>

Is it possible for me to add a function to the Web API result, which I can then use in the observableArray?

4
  • So do you mean there will be only one function to all rows myClickFunction and onclick of li you want to call myClieckFunction for perticular row? Commented Feb 14, 2015 at 4:04
  • @Dnyanesh yes, I would like an action to happen to each product when I click it. I tried jQuery binding, but the binding doesn't work for dynamically added elements. Commented Feb 14, 2015 at 5:54
  • 2
    Do you mean that the code of your myClickFunction comes from the server (returned by Web API call), or that you want to decorate each object with this function in your client code? If this is the former (which is not a good idea, actually), see this question, it it's the latter - just use array map function in your done() callback and add this callback to each of returned products. Commented Feb 14, 2015 at 12:40
  • @IlyaLuzyanin It's the latter. I was considering the former but I agree that it is not a good idea. I will try your suggestion, thank you! Commented Feb 15, 2015 at 8:17

1 Answer 1

1

You should consider your Product items as DTO's, and use proper view models in your front end code that can be passed such a DTO. For example, let's assume this server side class (since you haven't shown yours):

public class Product 
{
    public string Name { get; set; }
    public string Description { get; set; }
}

Then you could have a view model like this:

var ProductVm = function (dto) {
    var self = this;
    self.productName = dto.name;
    self.description = dto.description;
    self.myClickFunction = function() {
        // Your function...
    }
}

And pass them along these lines:

function listProducts(viewmodel) {
    var productsQuery = "api/products/get";

    // Send an AJAX request
    $.getJSON(productsQuery).done(function (result) {
        viewmodel.products(result.map(function (dto) { return new ProductVm(dto); }));
    });
}

Additionally, you may want to look at streamlining this to taste using the mapping plugin or by plainly extending self with the dto.

Sign up to request clarification or add additional context in comments.

1 Comment

That was exactly what I was trying to accomplish. I had a server-side model and a client-side model that was structurally equivalent. I was not familiar with how the map function would allow me to easily create the client-side object from the server-side data. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.