2
votes

Total newb question here, trying to get pointed in the right direction.

In an HTML template, I have a DOM element:

<a href=# data-bind="click: $parent.test">«</a>

In a Typescript file, I have:

public test() {
    alert("hello");
}

What should I be looking at in order to have the alert function get invoked by click?

Elaborating and adding some more context:

My ViewModel looks like this:

 import * as ko from 'knockout';
 import styles from './QuestCustomBlog.module.scss';
 import { IBlogPost, IBlogListings } from './IBlogListings';

 export interface IQuestCustomBlogPostBindingContext extends IBlogListings {
    shouter: KnockoutSubscribable<{}>;
 }

export interface IBlogListings {
    BlogPosts: IBlogPost[];
    Previous: string; //for paging backwards
    Next: string; // for paging forwards
}

export default class BlogListingsViewModel {

public BlogListings: KnockoutObservable<IBlogPost[]> = ko.observable(null);
public Next: KnockoutObservable<string> = ko.observable(null);    
public Previous: KnockoutObservable<string> = ko.observable(null);


constructor(bindings: IQuestCustomBlogPostBindingContext) {
    this.BlogListings(bindings.BlogPosts);
    this.Next(bindings.Next);
    this.Previous(bindings.Previous);

    bindings.shouter.subscribe((value: IBlogPost[]) => {
        this.BlogListings(value);
    }, this, 'BlogListings');

    bindings.shouter.subscribe((value: string) => {
        this.Next(value);
    }, this, 'Next');

    bindings.shouter.subscribe((value: string) => {
        this.Previous(value);
    }, this, 'Previous');


}

public test() {
    alert('test');
}
}

My ko.applybindings looks like this:

export default class QuestCustomBlogWebPart extends 
BaseClientSideWebPart<IQuestCustomBlogWebPartProps> {
  private _id: number;
  private _componentElement1: HTMLElement;
  private _koBlogSiteURL: KnockoutObservable<string> = ko.observable('');
  private _koBlogListings: KnockoutObservable<IBlogPost[]> = 
ko.observable(null);

  /**
   * Shouter is used to communicate between web part and view model.
   */
  private _shouter: KnockoutSubscribable<{}> = new ko.subscribable();

  /**
   * Initialize the web part.
   */
  protected onInit(): Promise<void> {
    this._id = _instance++;

    const tagName1: string = `BlogListingsComponent-${this._id}`;
    this._componentElement1 = this._createComponentElement(tagName1);
    ko.components.register(
        tagName1,
        {
            viewModel: BlogListingsViewModel,
            template: require('./BlogListingsTemplate.html'),
            synchronous: false
        }
    );

    this._getPagedBlogListings()
    .then((response) => {

      const bindings1: IQuestCustomBlogPostBindingContext = {
          BlogPosts: response.BlogPosts,
          shouter: this._shouter,
          Next: response.Next,
          Previous: response.Previous
      }
      ko.applyBindings(bindings1, this._componentElement1);

    })

    return super.onInit();
  }

All of the bindings you see work, except I can't seem to figure out how to bind the test() function to the click event...

1
The data-binding is as simple as you have it. Your test function though must be inside of the primary object that your UI is bound to. For example if you've called ko.applyBindings(viewModel), then test must be a function inside of "viewModel" - Jason Spake
Thanks @JasonSpake. I just added some more context to the original question to hopefully add more to the puzzle. - Henry Ong
I don't see the class BlogListingsViewModel being used anywhere. Knockout is getting bound to an anonymous object of IQuestCustomBlogPostBindingContext, but that doesn't have any references to the class you're trying to use. - Jason Spake
Sorry, left out some details that I thought weren't relevant. Just updated the original post again to give more context. - Henry Ong

1 Answers

1
votes

It’s a weird thing, but you can’t easly bind knockout event to prototype functions (And public Test() is this function).

Try changing test() into :

public test = ()=> {
    alert('test');
}

Edit : And I think you don’t need $parent in this case