4

Pretty new to knockout.js, I'm a C#'er but my new job involves a LOT more front end in addition to back-end so finally got round to this.

Anyway, I've encountered (what I think is) an unusual scenario where I want to call a viewModel method from a click event in JQuery; Perhaps this IS common but I can't quite figure it out:: Hoping someone can help!

I have a simple function in my viewModel file: //add to playlist
self.addToPlaylist = function (video) {
self.addedVideos.push(video);
};

I'm using a Jquery library called fancybox to load a number of images into a carousel so I have bound to my observableArray called videos

<div id="carousel" data-bind="foreach: videos">
             <!-- Left and right buttons -->
            <input id="left-button" type="button" value="" />
            <input id="right-button" type="button" value="" />
                <!-- All images with class of "cloudcarousel" will be turned into carousel items -->
                <!-- You can place links around these images -->
                <a class="fancybox-iframe" href="#" rel="group">
                    <img class="cloudcarousel" width="160" height="121" alt="test" data-bind="attr: {src: videoThumbnail, url: videoUrl, id: videoId, title: videoTitle, caption: videoCaption}"
                        onclick="previewVideo($(this).attr('url'), $(this).attr('caption'));CreateAddVideoClipButton($(this).attr('id'));" />                     
                </a>
            </div>    

This is the full html for this div. Ideally I would have click: $parent.addToVideos within the data-bind attributes on the but because the click I'm listening for doesn't happen at this stage I have to render an add button. The idea being that the click opens up the preview in fancybox and then the user can close the window, or click add to add this video to the array.

Ok, hopefully that makes sense to people...

In my Jquery method CreateAddVideoClipButton, I have:

var userModel = new VideosViewModel();
var text = "<a href='#' data-bind='click: userModel.addToPlaylist'>Add Video</a>";

and this is where I'm stuck. I need to know how to allow the click at this stage, call the addToPlaylist method in my viewModel

If you need any more info for this to make sense please let me know.


EDIT: POSTED CODE

ViewModel:

function VideosViewModel() {
    var self = this;

    //Array of videos
    self.videos = ko.observableArray([
        { videoTitle: "Video Title",
        videoId: "1",
        videoThumbnail: "images/image.png",
        videoAlt: "Alt text",
        videoUrl: "videos/video.mp4",
        videoCaption: 'video caption text' },

    ]);

    //Array of added videos
    self.addedVideos = ko.observableArray([]);

    //add to playlist
    self.addToPlaylist = function (video) {
        self.addedVideos.push(video);
        alert("Added to playlist");
    };

    //remove from playlist
    self.removeFromPlaylist = function (video) {
        self.addedVideos.remove(video);
    };
}
ko.applyBindings(new VideosViewModel());

HTML:

<div id="carousel" data-bind="foreach: videos">
             <!-- Left and right buttons -->
            <input id="left-button" type="button" value="" />
            <input id="right-button" type="button" value="" />
                <!-- All images with class of "cloudcarousel" will be turned into carousel items -->
                <!-- You can place links around these images -->
                <a class="fancybox-iframe" href="#" rel="group">
                    <img class="cloudcarousel" width="160" height="121" alt="test" data-bind="attr: {src: videoThumbnail, url: videoUrl, id: videoId, title: videoTitle, caption: videoCaption}",
                        onclick="previewVideo($(this).attr('url'), $(this).attr('caption'));CreateAddVideoClipButton($(this).attr('id'));" />                     
                </a>
            </div>  

ADD VIDEO CLIP FUNCTION

function CreateAddVideoClipButton(selectedVideoId) {
    var theElement = document.getElementById(selectedVideoId);
    var videoUrl = theElement.getAttribute('url');
    var videoThumb = theElement.getAttribute('src');
    var videoTitle = theElement.getAttribute('title');
    var videoId = theElement.getAttribute('id');
    selectedImageId = videoId;
    //var userModel = new VideosViewModel();
    var text = "<input type=\"button\" id=\"addButton\" class=\"addButton\" value=\"Add Video Clip\" onclick=\"addVideo(" + "'" + videoUrl + "'" + ", " + "'" + videoThumb + "'" + "," + "'" + videoTitle + "'" + "," + "'" + videoId + "'" + ");\" />";
    //var text = "<a href=\"#\" onclick=" + userModel.addToPlaylist() + "\">Add Video</a>";
    currentimageid = text;
    currentSelectedImageId = selectedImageId;
    hidePlayer();
}
Steve Greatrex
  • 15,789
  • 5
  • 59
  • 73
richardterris
  • 303
  • 2
  • 4
  • 13

4 Answers4

2

From what I understand you want to handle events unobtrusively.

It is plain simple if you look here:

http://knockoutjs.com/documentation/unobtrusive-event-handling.html

George Mavritsakis
  • 6,829
  • 2
  • 35
  • 42
2

I believe your problem is you are mixing onClick attributes and Knockout handlers, while instead you should just use the Knockout handlers. Using these handlers will take care of all boiler plate code like the one you added in the addVideoClipButton.

Example:

 <button data-bind="visible: showAddButton, click: $parent.addToPlaylist">Add to playlist</button>

I've copied your code to a fiddle, take a look at how you can simplify your code by making use of the Knockout handlers.

thomaux
  • 19,133
  • 10
  • 76
  • 103
  • 1
    Due to time constraints we ended up using plain jQuery for a lot of this, but over the holidays I intend to try re-writing the app with knockout from the ground up. I'll try your suggestion then and will mark as answer if it helps. Thanks for all the suggestions guys and merry Christmas to you all! – richardterris Dec 21 '12 at 15:35
0

I would do something like that

var VideosViewModel = {
    addToPlaylist : function () {
        alert("Added to playlist");
    }
};

ko.applyBindings(VideosViewModel);

$('#testBtn').click(function(){
    VideosViewModel.addToPlaylist();            
});
​

http://jsfiddle.net/VyUT4/4/

Nerdroid
  • 13,398
  • 5
  • 58
  • 69
0

You Can do something like this -

ViewModel -

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

    self.search = function (param) {
    //do something
    };

}

HTML -

<button data-bind="click: function () { Search() }" class="" id="searchBtn">Search</button>

Jquery -

function Search() {
// paramvalue = 1; 
viewModel.search(paramvalue);                  
}
Chetan Naithani
  • 271
  • 2
  • 9