开发者

What is the preferred method for passing server data to a RequireJS module?

Is there a preferred way to pass server data in a RequireJS module? Our current impl开发者_JS百科ementation looks like the following code snippets; using a 'page' object to hold any server/dynamic data and passing that to the main bootstrap. (We don't want to use ajax to populate any dependencies at this time)

From a server page :

<script data-main="scripts/main" src="scripts/require-jquery.js"></script>
<script type="text/javascript">
  define("page", function () {
      return { guid: "<%=Guid.NewGuid() %>" };
    });
</script>

main.js

require(["jquery", "jquery.alpha", "page"], function ($, alpha, page) {
    alpha.initialize(page);
});

jquery.apha.js

define(["jquery", "page"], function ($, page) {
    return {
        initialize: function () {
            console.log(page.guid);
            //logs guid as expected
        }
    }
});


I usually do something like this (using PHP on the back-end but anything works):

<script src="scripts/require-jquery.js"></script>
<script>
require(['scripts/main'], function(App) {
  var myApp = new App({
    param1: <?=json_encode($param1);?>,
    param2: <?=json_encode($param2);?>
  });
});
</script>

And then define my module as something that takes a config:

define(['jquery'], function($) {
  var App = function(options) {
    this.options = options;
    //blabla
  }

  // add some stuff to App.prototype maybe

  // and finally...
  return App;
});


RequireJS says nothing about how to deal with server data, as it is a means to modularize your javascript. So in that regard there is no defacto standard and you can combine RequireJS with json, ajax, php, embedded xml etc however you want.

Two Approaches

There generally are two ways to go about this.

  1. Model a 'dao' or 'service' module that gets the required data from the server and makes it accessible to its users (similar to your current approach, see code sample below)
  2. Define a global object to which all modules have access

The first approach adds parameters to your functions.

The second provides global access. This also requires your own initialization code to start fetching data.

It comes down to personal preference and how many of these 'dao's' you have. If you have more than one it might become poluting as you need a new parameter for each dao module. In that case making them global seems cleaner.

A problem with your approach

There is a problem with your current approach though, where you have the Page module as a definition (using define() instead of require()), because a define module is created for each object that depends on it. This potentially means multiple calls within the same page. Instead use:

// in seperate file page.js:
require([], function () {
  return { guid: "<%=Guid.NewGuid() %>" };
});

This way RequireJS recognizes page as a module because it is a seperate file and it will go to your server only once per page.


If you have a JSON object, make an AJAX call like @yves mentioned in the comments.

There are other options if you don't want to do that. You could put the guid as a data attribute on the script tag. Also, you could try making the loader js file dynamic so the config is set in that.

Honestly though, I'd just make an AJAX call.


I just started today with RequireJS and prior to this I was used to just call the function I wanted to execute on page load like this:

<script>
my_method(<?php echo json_encode( array('opt1'=>true, 'opt2'=>false) );?>);
</script>

As @ziad-saab I've found that the most similar thing I can do is not using the data-main attribute and just define an inline module:

<script src="path/to/require.js"></script>
<script>
require(['my/module'],function(module){
    module.my_method(<?php echo json_encode( array('opt1'=>true, 'opt2'=>false) );?>); 
});
</script>

The data-main attribute instructs RequireJS to execute the module as soon as require.js and all module dependecies are loaded. Omitting it (the module) and just defining it as an inline module I'm able to throw in PHP variables.

This way I don't need to handle with modules that hold my configurations and the transition to use requirejs is easier in my environment.


I have found some of the answers confusing, so here are the exact steps you need to follow to make it work for you:

In my case I am doing this like so:

index.php

<script src="/js/crm/lib/require.js"></script>
<script>
    // this is so called "named define"
    define('dto', {
        page: JSON.parse('{{ pageDTO | json_encode }}'),
        flashMessages: JSON.parse('{{ this.flashSession.getMessages() | json_encode }}')
    });
    // note we are using relative path to public dir here
    // order is also important, we need to define our dto module before bootstraping the application
    require(['/js/crm/app.js']);
</script>

app.js

"use strict";

require.config({
    // ...
    baseUrl: '/js/crm/lib',
    paths: { app: '../app' }
});

require(['app/bootstrap']);

some-module.js

(in this case layout.js that is required in app/bootstrap)

"use strict";

define([
    'dto',
    'jquery',
    'lodash'
], function (dto, $, _) { 
    console.log(dto);
});

Note using data-main to bootstrap the application, without explicit call to require might work, but due to race condition. If defining dto for some reason would take more than it takes requirejs to call main module script will crash. We don't want to rely on that, so we do everything ourselves :)

So this would not work (sometimes):

<script data-main="/js/crm/app.js" src="/js/crm/lib/require.js"></script>
<script>
    // this is so called "named define"
    define('dto', {
        page: JSON.parse('{{ pageDTO | json_encode }}'),
        flashMessages: JSON.parse('{{ this.flashSession.getMessages() | json_encode }}')
    });
</script>


Use window global variable to transfer server data into js application:

 <script type="text/javascript">
    window.server_data=parseJSON(<?php echo json_encode(array ("server_data"=>"it works!"));?>);
 </script>
 <script data-main="js/application" src="js/lib/require.js"></script>

in application.js:

requirejs(["app/main"],function (MyApp){
     console.dir(window.server_data); //all our application need this global variable
    var myApp=new MyApp();
    myApp.init(window.server_data); //and your application now has server data
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜