Search code examples
javascripttypescriptjsrenderjsviews

Need help using JsObservable with TypeScript?


I already worked with JSRender, JSViews and JSObservables in the past. This time, I started a new project but using TypeScript and I am not sure how to use it... I find very confusing where to put the references to .js, .d.ts, .ts...

Could I please describe what I have, where it fails and if you could spare some guidance.... it would give me a great start !

My "scripts" folder contains these files:

~\Typings\jQuery\jQuery.d.ts
installed from this NuGet package: jquery.TypeScript.DefinitelyTyped v0.0.1

~\Typings\jsrender\jsrender.d.ts   
installed from this NuGet package: jsrender.TypeScript.DefinitelyTyped v0.1.8

File: ~/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="scripts/jquery-3.1.1.js"></script>
    <script src="scripts/jsviews.js"></script>
    <script src="scripts/game/game.js"></script>
    <script src="scripts/game/app.js"></script>
</head>
<body>
    <div id="view">
        <div id="myMap"></div>
        <div id="optionsTmpl"></div>
    </div>
</body>
</html>

File: ~/tmpl/options.tmpl.html

<div class="optionsFrame">
    <select data-link="mapType">
    {^{for mapTypes}}
        <option value="{{:id}}">{{:name}}</option>
    {{/for}}
    </select>
    <input type="button" value="test">
</div>

File: app.ts

/// <reference path="../typings/jquery/jquery.d.ts" />
/// <reference path="../typings/jsrender/jsrender.d.ts" />
class UnchartedApp {
    game: UnchartedGame;

    init() {
        this.game = new UnchartedGame();
        this.game.loadMap();
    }
}

window.onload = () => {
    var app = new UnchartedApp();
    app.init();
};

File: game.ts

/// <reference path="../typings/jquery/jquery.d.ts" />
/// <reference path="../typings/jsrender/jsrender.d.ts" />
class UnchartedGame {
    constructor() {
    }


    /*****      Error on the $.observe() line !!    *****/
    loadMap() {
        this.linkTemplate("options", "#optionsTmpl", this).done(function (currentGame) {
            $.observe(currentGame, "*", currentGame.modelChangeHandler);
        });
    }

    modelChangeHandler(ev, eventArgs) {
        if (ev.type == "propertyChange") {
            var _game: UnchartedGame = ev.currentTarget;
            if (eventArgs.path == "mapType") {
                try {
                    _game.myMap.setMapType(mapTypeNames[newValue]);
                }
                catch (ex) {
                }
            }
        }
    }

    loadTemplate(tmplName: string) {
        var deferredLoad = $.Deferred();
        try {
            var filePath: string = "../tmpl/" + tmplName + ".tmpl.html";
            $.get(filePath).then(function (templateText) {
                $.templates(tmplName, templateText);
                deferredLoad.resolve();
            })
        }
        catch (e) {
            deferredLoad.reject();
        }
        return deferredLoad.promise();
    }

    linkTemplate(tmplName: string, targetId: string, model: UnchartedGame) {
        var deferredLink = $.Deferred();
        try {
            this.loadTemplate(tmplName).done(
            function () {
                $.templates[tmplName].link(targetId, model);
                deferredLink.resolve(model);
            });
        }
        catch (e) {
            deferredLink.reject();
        }
        return deferredLink.promise();
    }
}

Thanks and regards,

Claude


Solution

  • TypeScript wants you to use ES6 import statements ie: import * as jQuery from 'jquery'; The other way to do it is to reference the script (jquery, for example) in your module loader and then use declare const jQuery: any to be used throughout your application. Another way to do is to reference the typings in your tsconfig:

    First way using import statements:

    import * as jQuery from 'jquery'; // jquery installed via npm install jquery
    import * as jsrender from 'jsrender'; // jsrender installed via npm install jsrender
    
    // === OR ===
    
    declare const jQuery: any; // Reference the script in your module loader/html
    declare const jsrender: any; // Reference the script in your module loader/html
    
    class UnchartedGame {
        constructor() {
        }
    
    
    /*****      Error on the $.observe() line !!    *****/
    loadMap() {
        this.linkTemplate("options", "#optionsTmpl", this).done(function (currentGame) {
            $.observe(currentGame, "*", currentGame.modelChangeHandler);
        });
    }
    
    modelChangeHandler(ev, eventArgs) {
        if (ev.type == "propertyChange") {
            var _game: UnchartedGame = ev.currentTarget;
            if (eventArgs.path == "mapType") {
                try {
                    _game.myMap.setMapType(mapTypeNames[newValue]);
                }
                catch (ex) {
                }
            }
        }
    }
    
    loadTemplate(tmplName: string) {
        var deferredLoad = $.Deferred();
        try {
            var filePath: string = "../tmpl/" + tmplName + ".tmpl.html";
            $.get(filePath).then(function (templateText) {
                $.templates(tmplName, templateText);
                deferredLoad.resolve();
            })
        }
        catch (e) {
            deferredLoad.reject();
        }
        return deferredLoad.promise();
    }
    
    linkTemplate(tmplName: string, targetId: string, model: UnchartedGame) {
        var deferredLink = $.Deferred();
        try {
            this.loadTemplate(tmplName).done(
            function () {
                $.templates[tmplName].link(targetId, model);
                deferredLink.resolve(model);
            });
        }
        catch (e) {
            deferredLink.reject();
        }
        return deferredLink.promise();
    }
    

    }

    Using TSConfig:

    {
      "compilerOptions": {
        "types": ["jquery", "jsrender"]
      }
    }
    

    One other possible way is to go to your main module and use the following line:

    import 'jquery'; // jquery installed via npm install jquery

    I noticed that's how I'm using it in one of my projects (required @types file).

    I would also recommend getting away from using reference paths as TypeScript is all about types. Most modules (from what I've seen thus far) come with a typings file. However, jQuery for example does not. So, after you do npm install jquery, you'll want to additionally install it's typings by running npm install @types/jquery --save-dev