1

I want to assign a array value into a variable in knockoutjs. I can iterate over a array by for loop. My code is

<!-- ko foreach: {data: friends, as: 'friend'} --> 
<span data-bind="text:friend"></span> 
<!-- /ko -->

<script type="text/javascript">

    var viewModel = {
        firstname: ko.observable("X"),
        lastname: ko.observable("Y"),
        friends: ko.observableArray(["A", "B"]),
        books: ko.observableArray(["Book1", "Book2"]),
    };
    viewModel.fullname = ko.dependentObservable(function () {
        return this.firstname() + " " + this.lastname();
    }, viewModel);
    ko.applyBindings(viewModel); 
</script>

But I want book's first element and then iterate over friends. Like

<!-- ko {books()[0], as : 'book'} -->
<!-- ko foreach: {data: friends, as: 'friend'} -->

<span data-bind="text:friend"></span>
<span data-bind="text:book"></span>

<!-- /ko -->
<!-- /ko -->

I know my approach is wrong. But I cann't figure out how can i get first book's element and then iterate through friends.

5
  • can you throw some light on the relationship between books and friends? By what you are trying to achieve, I guess you want to establish some kind of parent child relation between books and friends... Commented Nov 17, 2016 at 6:42
  • @gkb This is only an example. I want to use it to another purpose. Only need to know how can I assign the first books element in book and use this variable in friends loop. Commented Nov 17, 2016 at 6:45
  • is this what you want - jsfiddle.net/mxq63qzm ? Commented Nov 17, 2016 at 6:47
  • Almost. But I want to use book variable in the loop. And it's not working. Commented Nov 17, 2016 at 6:51
  • Make another computed observable that returns an object with the book and friends. Commented Nov 17, 2016 at 7:04

1 Answer 1

1

Three ways to do this:

  1. Create a custom binding to add stuff to the binding context
  2. Create new viewmodels for your friend-book combinations
  3. Use the $parent or $root keyword, doesn't allow you to define a new variable name

1. Using a custom binding

Based on this example, you could extend the binding context. Note that foreach also creates a new binding context, so you'll still have to use $parent. You could also extend the standard foreach binding to include an extra parameter for extending the binding context (to get rid of $parent).

var viewModel = {
  firstname: ko.observable("X"),
  lastname: ko.observable("Y"),
  friends: ko.observableArray(["A", "B"]),
  books: ko.observableArray(["Book1", "Book2"]),
};

ko.bindingHandlers.withProperties = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // Make a modified binding context, with a extra properties, and apply it to descendant elements
        var innerBindingContext = bindingContext.extend(valueAccessor);
        ko.applyBindingsToDescendants(innerBindingContext, element);
 
        // Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
        return { controlsDescendantBindings: true };
    }
};
ko.virtualElements.allowedBindings.withProperties = true;
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<!-- ko foreach: { data: friends, as: 'friend' } -->
<!-- ko withProperties: { book: $parent.books()[0] } -->
<span data-bind="text:friend"></span>
<span data-bind="text:book"></span>
<!-- /ko -->
<!-- /ko -->

2. Creating new viewmodels

I think this is the "purest" viewmodel - view solution.

var viewModel = {
  firstname: ko.observable("X"),
  lastname: ko.observable("Y"),
  friends: ko.observableArray(["A", "B"]),
  books: ko.observableArray(["Book1", "Book2"]),
};

viewModel.bookFriendCombos = ko.pureComputed(function() {
  var book = viewModel.books()[0];
  return viewModel.friends().map(function(friend) {
      return {
        friend: friend,
        book: book
      };  
  });
});


ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<!-- ko foreach: bookFriendCombos -->
<span data-bind="text:friend"></span>
<span data-bind="text:book"></span>
<!-- /ko -->

3. Using $parent

Probably the easiest to implement and, as long as your view remains simple, I'd prefer this one.

var viewModel = {
  firstname: ko.observable("X"),
  lastname: ko.observable("Y"),
  friends: ko.observableArray(["A", "B"]),
  books: ko.observableArray(["Book1", "Book2"]),
};
viewModel.fullname = ko.dependentObservable(function() {
  return this.firstname() + " " + this.lastname();
}, viewModel);
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<!-- ko foreach: {data: friends, as: 'friend'} -->
<span data-bind="text:friend"></span>
<span data-bind="text:$parent.books()[0]"></span>
<!-- /ko -->

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

Comments

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.