Calling Knockout.js viewModel function from JQuery onclick

richardterris picture richardterris · Dec 19, 2012 · Viewed 11k times · Source

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();
}

Answer

George Mavritsakis picture George Mavritsakis · Dec 20, 2012

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