使用JSViews在下拉列表中的复杂对象

时间:2017-11-21 22:05:51

标签: jsfiddle jsrender jsviews

我正在使用JSViews,Observables和TypeScript进行项目。 我打算处理几种语言,所以我有一个包含法语和英语版本的对象。一个带有静态方法的类,它返回名称集合和一个包含所有静态对象的数组。

我想在下拉列表中使用转换器显示对象以获取英文名称,我设法填写下拉列表并对更改做出反应,但我无法在下拉菜单中显示当前项目,而我不会#39 ;看看缺少什么。

你可以帮忙吗?我在这里制作了一个javascript示例:     https://jsfiddle.net/ClaudeVernier/v093uqg0/

var data = new dataModel();
    for (var member in Harbors) {
  if (typeof Harbors[member] == "object" && Harbors[member].name) {
    data.harbors.push(Harbors[member]);
  }
}

var myTmpl = $.templates("#harborTmpl");
myTmpl.link("#container", data);
    $.observe(data, "*", myHandler);

然后,我需要弄清楚如何通过点击按钮来改变语言,如果您对此有所了解......它会有所帮助: - )

非常感谢, 克劳德

3 个答案:

答案 0 :(得分:2)

查看Data-linked <select> elements - 包括<select> with converters部分。

您的代码:

<select id="cboHarbor" data-link="{{getName:activeHarbor}}">

不正确。您需要数据链接到activeHarbor。如果activeHarbor是一个字符串,您可以使用以下数据进行数据链接:

<select id="cboHarbor" data-link="activeHarbor">

但由于它是一个对象,您需要为每个港口对象提供某种字符串值属性,然后您可以将其用于每个选项值。然后,您将使用转换器在activeHarbor对象及其字符串值属性之间来回转换,以实现数据链接绑定行为。

例如,您可以使用当前语言中的名称作为字符串值,但使用基于当前语言更改的值有点奇怪。但是你需要一个getHarbor转换器来转换回来从名称到港湾对象。这看起来像这样:

<select id="cboHarbor" data-link="{getName:activeHarbor:getHarbor}">
  {^{for harbors}}
    <option data-link="{getName:}"></option>
  {{/for}}
</select>

或者,您可以使用数组中港口的索引,如下所示:

<select id="cboHarbor" data-link="{getIndex:activeHarbor:getHarbor}">
  {^{for harbors}}
    <option value="{{:#index}}" data-link="{getName:}"></option>
  {{/for}}
</select>

转换器如下:

$.views.converters({
  getIndex: function (harbor) {
    return harbor.index;
  },
  getHarbor: function (index) {
    return data.harbors[index];
  },
  getName: function (harbor) {
    return harbor.name[data.languages[data.currentLanguage]];
  }
});

如果您希望能够动态更改语言并将港口下拉菜单切换为新语言,则必须使getName转换器依赖于当前语言,如下所示:

$.views.converters.getName.depends = [data, "currentLanguage"];

这是一个updated version of your jsfiddle完整的语言下拉菜单,用于切换语言。

更新:

关于depends的{​​{1}},modified jsFiddle有这个:

getName

因此,您只需使用function getName(harbor) { return harbor.name[data.languages[data.currentLanguage]]; } $.views.converters({ getName: getName, ... }); getName.depends = [data, "currentLanguage"]; 函数作为转换函数,然后在您可以访问数据实例的上下文中(如果需要异步,则在getName中),然后你分配了依赖:

done()

无需使用getName.depends = [data, "currentLanguage"];

答案 1 :(得分:0)

我遇到了在TypeScript中定义的对象上调用JSObservable.depends方法的问题。 我创建了一个小版本的网页,其中显示了城市的下拉列表,当前城市的名称以及该语言的选项。

我有语言和城市(港口)课程,两个IJSViews *接口,可以在转换器中编译代码

UnchartedGame类就是它发生的地方,它的GetName方法是转换器调用的方法,Init方法加载数据模型并加载模板。

模板链接后,我想设置依赖性,以便使用以下行设置城市下拉列表切换语言的内容:         currentGame.GetName.depends = [currentGame,&#34; activeLanguage&#34;]; 但是对于&#34;编译器&#34;它不起作用,依赖不是GetName方法的方法!

我有三个文件:

的index.html

<script type="text/javascript" src="scripts/jquery-3.2.1.js"></script>
<script type="text/javascript" src="scripts/js/jsrender.js"></script>
<script type="text/javascript" src="scripts/js/jquery.observable.js"></script>
<script type="text/javascript" src="scripts/js/jquery.views.js"></script>
<script type="text/javascript" src="scripts/game/game.js"></script>

<div id="view" style="padding: 5px;">
    <div id="optionsTmpl"></div>
</div>

options.tmpl.html

    <select id="cboHarbor" data-link="{getIndex:activeHarbor:getHarbor}">
        {^{for harbors}}
        <option value="{{:#index}}" data-link="{getName:}"></option>
        {{/for}}
    </select>
    <select id="cboLanguage" data-link="activeLanguage">
        {^{props languages}}
        <option>{{:key}}</option>
        {{/props}}
    </select>

game.ts

/// <reference path="../typings/jquery/jquery.d.ts" />
/// <reference path="../typings/jsrender/jsrender.d.ts" />

window.onload = () => {
    let game: UnchartedGame;
    this.game = new UnchartedGame();

    $.views.converters({
        getIndex: function (harbor) {
            return harbor.index;
        },
        getHarbor: function (index) {
            return this.ctx.root.harbors[index];
        },
        getName: this.game.GetName
    });
    this.game.load();
};

/*
 * INTERFACES
 */

interface IDictionnary {
    [idx: number]: string;
}

interface IHasName {
    name: IDictionnary;
}

interface IJSViewsContextHolder {
    ctx: IJSViewsRootHolder
}

interface IJSViewsRootHolder {
    root: UnchartedGame
}

interface IHarbor {
    index: number;
    name: IDictionnary;
}

/*
 * CLASSES
 */

class Languages {
    ["English"] = 0;
    ["French"] = 1;
}

class GameStrings {
    static Brest: IDictionnary = {
        ["English"]: "Brest",
        ["French"]: "Brest"
    };

    static London: IDictionnary = {
        ["English"]: "London",
        ["French"]: "Londres"
    };

    static QuebecCity: IDictionnary = {
        ["English"]: "Quebec city",
        ["French"]: "Ville de Québec"
    };
}

class Harbor implements IHarbor, IHasName {

    public index: number = 0;

    /*  Methods    */
    constructor(public name: IDictionnary) {
    }
}

class Harbors {

    static Brest: IHarbor = new Harbor(
        GameStrings.Brest
    );

    static London: IHarbor = new Harbor(
        GameStrings.London
    );

    static QuebecCity: IHarbor = new Harbor(
        GameStrings.QuebecCity
    );
}

class UnchartedGame {

    public activeLanguage: string = "English";

    public languages: Languages = new Languages();
    public activeHarbor: Harbor = null;
    public harbors: Array<Harbor> = null;
    public ctx: IJSViewsRootHolder; 
    constructor() {
    }
    GetName(harbor: IHarbor): any {
        return harbor.name[(this as IJSViewsContextHolder).ctx.root.activeLanguage];
    }
    load() {
        let idx: number = 0;
        this.harbors = new Array<Harbor>();

        for (var member in Harbors) {
            Harbors[member].index = idx++;

            if (!this.activeHarbor) {
                this.activeHarbor = Harbors[member];
            }

            this.harbors.push(Harbors[member]);
        }

        this.linkTemplate("options", "#optionsTmpl", this).done(function (currentGame: UnchartedGame) {
            //currentGame.GetName.depends = [currentGame, "activeLanguage"];
        });
    }

    loadTemplate(tmplName: string) {
        var deferredLoad = $.Deferred();

        try {
            var filePath: string = "../" + 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();

        this.loadTemplate(tmplName).done(
            function () {
                $.templates[tmplName].link(targetId, model);
                deferredLink.resolve(model);
            }
        );

        return deferredLink.promise();
    }
}

我花了一些时间试图明确这一点,并试着让它适合这里,我希望它足够清楚,让你明白。

此致 克劳德

答案 2 :(得分:-1)

谢谢!

适用于港口,我之前和之后都没想过转换器。

对于本地化,因为我用TypeScript编写它,$ .views.converters.getName.depends没有编译所以我试图在linkTemplate之后添加它:

this.linkTemplate("options", "#optionsTmpl", this).done(
      function (currentGame: UnchartedGame) {
                $.observe(currentGame, "*", currentGame.gameModelChangeHandler);

                $.views.converters["getName"].depends = [currentGame, "activeLanguage"];
       }
 );

它似乎不起作用,可能是因为[&#34; getName&#34;]还是其他地方?

这是一个我作为业余爱好开始的项目,它处于早期阶段,可以在这里看到:http://unchartedwaters2.azurewebsites.net/ : - )