skip to Main Content

I’m learning more about knockout.js. I want to add images to my text data, and display the correct one based on the image link provided in the array with it’s matching data. I only want one set to show at a time, so in other words it replaces the data. I don’t quite grasp how the data binding stuff works just yet, and how everything displays. I’m stumbling my way through figuring it out.

What I sort of have figured out is the text part, but I’m lost on adding images based on the sets below.

Here’s a short example of my data:

 const story = 

  //-------------------------------Initiate Chat
  {"1":{"text":"Pick a chat",
  "image":"http://placekitten.com/300/200",
  "choices":[{"choiceText":"Pick This","storyLink":"2"},{"choiceText":"no pick this","storyLink":"3"},{"choiceText":"nono this one","storyLink":"4"},{"choiceText":"dont pick this","storyLink":"5"},]},
  
   //-------------------------------Chat 1 test
  "2":{"text":"Kittens",
  "image":"https://placekitten.com/300/100",
  "choices":[{"choiceText":"Oops. Scared them.","storyLink":"3"}]},

  "3":{"text":"They are no longer scared",
  "image":"https://placekitten.com/300/100",
  "choices":[{"choiceText":"Poor things.","storyLink":"3"}]},
  
}

An example of working code would help me the most. I keep getting "Unable to Process Binding" Error when I have tried figuring it out. I can’t seem to find specific examples where the images are being called along with other data like text as shown above. I appreciate the help!

For example: Knockout Image Not display while binding image and text at same time

this sort of answers my question but I’m not sure how to do it with an array. Should I be using a forEach?

2

Answers


  1. You use the tag with the attr knockout binding to display images. Example:

    <img data-bind="attr: {src: 'https://placekitten.com/300/100'}">
    

    See this working example:

    https://jsfiddle.net/martlark/9v028d4z/34/

    Login or Signup to reply.
  2. I think it’s a good idea to introduce some view models that make it easier to work with your story format.

    In the example below, I created two:

    • StoryVM
      • tracks the currently active section and returns its details
    • ChoiceVM
      • adds an onClick handler that sets the active story to each choice,
      • takes the storyLink and looks up the corresponding image in the data

    Once you have your image urls properly mapped between the choices and the main story chunks, you can use the attr: { src } binding to apply it to an image.

    To prevent broken images when no src is available, I’ve wrapped the <img> tag in an if binding.

    const StoryVM = (model, startId) => {
      const activeStoryId = ko.observable(startId);
    
      const activeStory = ko.pureComputed(() => {
        const data = model[activeStoryId()]
    
        return {
          ...data,
          choices: data.choices.map(ChoiceVM)
        };
      });
    
      const ChoiceVM = ({
        choiceText,
        storyLink,
      }) => {
        return {
          image: storyModel[storyLink]?.image,
          text: choiceText,
          onClick: () => {
            activeStoryId(storyLink);
          }
        }
      }
    
    
      return activeStory;
    }
    
    const storyModel = {"1":{"text":"Pick a chat","image":"http://placekitten.com/300/200","choices":[{"choiceText":"Pick This","storyLink":"2"},{"choiceText":"no pick this","storyLink":"3"},{"choiceText":"nono this one","storyLink":"4"},{"choiceText":"dont pick this","storyLink":"5"}]},"2":{"text":"Kittens","image":"https://placekitten.com/300/100","choices":[{"choiceText":"Oops. Scared them.","storyLink":"3"}]},"3":{"text":"They are no longer scared","image":"https://placekitten.com/200/100","choices":[{"choiceText":"Poor things.","storyLink":"3"}]}};
    
    ko.applyBindings({
      story: StoryVM(storyModel, "1")
    });
    .Choices {
      display: flex;
      gap: 1rem;
    }
    
    .Choice {
      display: flex;
      flex-direction: column;
      width: 200px;
      height: 150px;
      justify-content: flex-end;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    
    <div data-bind="with: story">
      <!-- ko if: image -->
      <img data-bind="attr: { src: image }">
      <!-- /ko -->
    
      <h2 data-bind="text: text"></h2>
    
      <div data-bind="foreach: choices" class="Choices">
        <div class="Choice">
          <!-- ko if: image -->
          <img data-bind="attr: { src: image }">
          <!-- /ko -->
          <button data-bind="click: onClick, text: text"></button>
        </div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search