dojo JsonRest call not working - dojo

I'm trying to call my RESTful service from dojo. All I can see from debugger is, it tries to call the service but it doen't reach there. There are no errors. I can see the 'hello' alert.
define(["dojo/store/JsonRest","dojo/domReady!"],
function(JsonRest){
alert("Hello");
var rest = new JsonRest({
target: "/my/rest/call"
});
}
);
I's following this page from dojotoolkit.
But if i call using a declare then it works.
define(["dojo/store/JsonRest","dojo/_base/declare","dojo/domReady!"],
function(JsonRest, declare){
var rest = declare(JsonRest);
var restResult = new rest({
target: "/my/rest/call"
});
}
);
What am I doing wrong here?
error messages in console:

You're not following that tutorial to the letter. The difference is that you're using define and not require. Dojo's define is used in combination with declare to create new Dojo classes. Dojo's require is used to load and use existing classes. The link below is a recommended read and in your case pay special attention to the 'Requiring modules' and 'Defining modules' parts:
https://dojotoolkit.org/documentation/tutorials/1.8/modules/
If you use require like in that tutorial, it works perfectly:
require([
'dojo/store/JsonRest',
], function(
JsonRest
) {
new JsonRest({
target: 'some/resource/'
}).get(1).then(function (item) {
alert(JSON.stringify(item));
});
});
Here's a working example on Plunker: http://plnkr.co/edit/ZhsO67BFpWB5Txqy0Zl9?p=preview

Related

How to use dojo On with Dojox Searchbox?

I am following this link http://dojotoolkit.org/reference-guide/1.9/dojox/mobile/SearchBox.html and am trying to do the same in my app. The only difference is that I want to use "onSearch" event using "dojo On" but I am not able to read results, query, options that we get by default in the onSearch function.Please help me in solving this problem.
My HTML code:
<input data-dojo-type="dojox/mobile/SearchBox" type="search" placeHolder="Search"
data-dojo-props='store:store, searchAttr: "label", ignoreCase: true, pageSize:2'>
<ul data-dojo-type="dojox/mobile/RoundRectList" jsId="list"></ul>
My JS code:
define(["dojo/has",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/array",
"dojo/dom",
"dojo/dom-class",
"dojo/dom-construct",
"dojo/query",
"dojo/dom-style",
"dojo/dom-attr",
"dojo/on",
"dojo/_base/Deferred",
"dojo/topic",
"dojo/_base/connect",
"dijit/registry",
"dojo/store/Memory",
"dojox/mobile/SearchBox",
"dojo/selector/acme"
],
function(has,declare,lang,array,dom,domClass,domConstruct,query,domStyle,domAttr,on,Deferred,topic,connect,registry,MemoryStore,SearchBox)
{
declare("controllers.SearchController", [], {
started:false,
constructor : function(args) {
WL.Logger.debug("SearchController created");
lang.mixin(this,args);
},
start:function(){
if(!this.started)
{
console.log("i am in SearchController.start");
this.subscription();
this.started = true;
}
},
subscription:function(){
store = new MemoryStore({data: [
{label: "Alabama"},
{label: "Alaska"},
{label: "American Samoa"},
{label: "Arizona"},
{label: "Arkansas"},
{label: "Kansas"},
{label: "Kentucky"}
]});
var searchbox=registry.byId("searchbox");
on(searchbox.domNode,"search",lang.hitch(this,this.onSearch));
},
onSearch: function (results, query, options) {
// this.onSearch = function () {};
console.log(results);
}
});
return controllers.SearchController;
}
);
Also, I am following this link dojox/mobile/SearchBox 'onSearch' event runs twice on webkit
to use the workaround for dojox searchbox. How can I implement it in my case?
You should never try to access widget events through DOM nodes. There is a difference between widgets and DOM nodes, and this is one of them. Also, because dojo/on can only be used with DOM nodes and DOM events, you cannot use it to handle the onSearch event.
Every widget has a on() function that you can use to attach widget event handlers. For example:
searchbox.on("search", lang.hitch(this, this.onSearch));
If the event runs twice, you can try doing something like this (you will probably have to rewrite this in your object oriented design):
var myEventHandler = searchbox.on("search", lang.hitch(this, this.onSearch());
myEventHandler.remove();
According to the API documentation the return value of the on() function is undefined, but this topic its stated that it returns an object containing a remove() function able to remove the event listener.
I don't think it's possible. If you want to retrieve data from your database/webservice, you could use the dojo/store/JsonRest store (RESTful webservices) or you could implement your own store (or fetch the data and put it in a dojo/store/Memory).
Dojo chooses for an abstraction layer upon your data implementation called the store API. The advantages of these are that, because it's an abstraction layer, that you can use your store for multiple purposes (all Dijit widgets, Dojo mobile widgets, ...) work in a similar way that they use a store.
Concerning this part of your question:
I am following this link dojox/mobile/SearchBox 'onSearch' event runs twice on webkit to use the workaround for dojox searchbox. How can I implement it in my case?
I do not think such a workaround is needed. As I wrote in this answer, as long as you have a store specified, SearchBox.onSearch() should be called only once.
In short: just do not apply this workaround, it shouldn't be necessary.
In addition to the event mistake pointed out by Dmitri, there's an issue with the order of execution.
When does Dojo parse your HTML? Do you have parseOnLoad:true in your dojoConfig (or data-dojo-config)?
When the parser reaches data-dojo-type="dojox/mobile/SearchBox", it will try to instantiate a SearchBox widget. Because you have specified store:store in its properties, it will look for a variable called store.
Now, the store variable itself gets instantiated in your SearchController. So you have to make sure that subscription() is called before the parser runs. However, the subscription() method in turn tries to look for a widget called "searchbox". So the parser has to be called before subscription(). As you can tell, this isn't going to work :)
So you have to rewrite the SearchController a bit. For example, you can remove the store:store from data-dojo-props, and let the controller set it in the subscription method:
var store = new MemoryStore({data: [....]});
var searchbox = registry.byId("searchbox");
searchbox.set("store", store);
searchbox.on("search", lang.hitch(this, this.onSearch)); // See Dmitri's answer.

Dojo provide - update legacy to AMD

This is a followup to this question.
So I have this pre AMD dojo code :
dojo.require(...);
dojo.provide("abc.def.foo");
som.var.iable = {A:1,B:2};
som.var.iable2 = {C: 3, D:som.var.iable.B}
dojo.declare("blah",[],{
//code based on the above variables
});
For AMD, after reading this and the previous link, I am trying something like this
som.var.iable = {A:1,B:2};
som.var.iable2 = {C: 3, D:som.var.iable.B}
define([
"dojo/_base/declare",
], function(declare){
return declare("abc.def.foo", null {
});
});
define([
"dojo/_base/declare",
], function(declare){
som.var.iable = {A:1,B:2};
som.var.iable2 = {C: 3, D:som.var.iable.B}
return declare("blah", null {
//code based on the above variables
});
});
Obviously this fails, as there is no object structure like som.var.iable. I can it, but my question is how did it work in the legacy code? and what would be the correct AMD equivalent?
Any help is greatly appreciated!
OK, here are my assumptions about what you're trying to do:
You don't really need a global variable called some with a property var, that's just a way to organize stuff
You want three modules, some/var/iable, some/var/iable2, and blah. This means three files and three define() calls
Neither som.var.iable nor som.var.iable2 are real inheritable classes, they're just plain old objects... so only blah needs to use declare()
Thus you should create a file som/var/iable.js, which is a provides a plain object:
define([
],
function(){
return {A:1,B,2}
});
And another called som/var/iable2.js, which is a module that provides a plain object:
define([
"som/var/iable",
],
function(iable){
return {C: 3, D:iable.B}
});
And then your third module blah.js that provides a Class-object:
define([
"dojo/_base/declare",
"som/var/iable2"
],
function(declare,iable2){
var parentClasses = [];
var clazz = declare(parentClasses, {
constructor : function(){
// No need for this.inherited(arguments) in this particular case
alert("Welcome to the constructor. Did you know that iable2.D is "+iable2.D+"?");
},
});
return clazz;
});
I haven't tested all this, but to kick it off in a page you'd finally want to put:
require(["blah",dojo/domReady!"], function(blah){
var b = new blah();
});
Dojo should take care of loading everything in-order so that you get an alert that says
Welcome to the constructor. Did you know that iable2.D is 2?

How to structure a complex web app with RequireJS

I saw there is somes questions related to mine (like this interesting one), but what I wonders is how to do it correctly, and I couldn't find it via the others questions or the RequireJS documentation.
I'm working on a quite heavy web application that will run in only one html page.
Before RequireJS, I used to do a lot of JS modules with public methods and connecting them via the on event on the Dom READY method, like this :
var DataList = function () {
this.base = arguments[0];
this.onUpdate = function (event) { ... }
}
$(function () {
var dataList = {}; DataList.apply(dataList, [$('#content')]);
$('table.main', dataList.base).on ('update', dataList.onUpdate);
});
With RequireJS, I can easily see that I can split DataList and all others classes like this on individual files, but what about the $(function () {}); part?
Can I still keep it this way, but instead of the DOM ready function of jQuery, I put the events on the main function() of the RequireJS, when my primary libs are loaded?
Or do I have to change the way I create JS "classes", to include a init function maybe, that will be called when I do a, for example :
require(['Datalist'], function(dataList) {
dataList.init($('#content'));
});
What annoys me the most is that since I have only one html file, I'm afraid the require() will have to load a huge list of files, I'd prefer it to load just libs that, them, would load sub libs required to work.
I don't know, the way of thinking with RequireJS lost me a bit :/
How would you do?
"Can I still keep it this way, but instead of the DOM ready function of jQuery, I put the events on the main function() of the RequireJS, when my primary libs are loaded?"
If you separate the functions or 'classes' into modules then you can use the RequireJS domReady function:
require(['module1'], function(module1) {
domReady(function(){
// Some code here ftw
})
});
The benefit here is the domReady function will allow downloading of the modules instantly but won't execute them until your DOM is ready to go.
"Or do I have to change the way I create JS "classes", to include a init function maybe, that will be called when I do a, for example"
You won't need to change the way you interact with your code this way, but you can probably improve it. In your example I would make DataList a module:
define(function(require) {
var $ = require('jquery');
var DataList = function () {
this.base = arguments[0];
};
DataList.prototype.onUpdate = function() {
};
return DataList;
});
require(['data-list'], function(DataList) {
var data = {};
// Call DataList with new and you won't need to set the context with apply
// otherwise it can be used exactly as your example
new DataList(data);
});
"What annoys me the most is that since I have only one html file, I'm afraid the require() will have to load a huge list of files, I'd prefer it to load just libs that, them, would load sub libs required to work."
Make your code as modular as you want/can and then use the optimiser to package it into one JS file.

using dijit.byId w dojox.mobile widgets

I'm dynamically building a series of dojox.mobile.ListItem widgets under a statically defined dojox.mobile.RoundRectList widget via this function...
function displayOpps(items) {
// Create the list container that will hold application names
var rrlOppsContainer = dijit.byId("rrlOpps");
// Add a new item to the list container for each element in the server respond
for (var i in items){
// Create and populate the list container with applications' names
var name = items[i].CustName + " - " + items[i].OppNbr;
var liOpps = new dojox.mobile.ListItem({
label: name,
moveTo: "sv3OppDetail"
});
// Add the newly created item to the list container
rrlOppsContainer.addChild(liOpps);
}
}
When I run this code during onLoad() in my html file, I get the following error using Chrome's dev tools...
Uncaught TypeError: Object # has no method 'byId'
I've read numerous articles around this topic and it appears that lots of folks have this problem, but each that I have found are in relation to some other technology (e.g., Spring MVC, etc) and I'm attempting to use it w a dojox.mobile based app. That said, I attempted to mimic some of the solutions brought up by others by including this in my html file, and it still doesn't work...
<script type="text/javascript"
data-dojo-config="isDebug: true, async: true, parseOnLoad: true"
src="dojo/dojo.js">
dojo.require("dojox.mobile.RoundRectList")
</script>
What am I doing wrong?
Thank you in advance for your time and expertise.
If you are using Dojo 1.7+, you probably just forgot to require the "dijit/registry" module. This where the byId function is defined. When you use desktop widgets, this is loaded indirectly by other base modules, but with dojox/mobile you must load it explicitly (because dojox/mobile loads only a very minimal set of modules by default, to minimize code footprint).
Depending on how you wrote your application, do this:
dojo.require("dijit.registry"); // legacy (pre-1.7) loader syntax
...
var rrlOppsContainer = dijit.byId("rrlOpps");
...
or this:
require(["dijit/registry", ...], function(registry, ...){ // 1.7+ AMD loader syntax
...
var rrlOppsContainer = registry.byId("rrlOpps");
...
});
Note also that your second code sample tries to use asynchronous loading (async: true) while it uses the legacy loader syntax. This won't work, to get async loading you must use the AMD syntax.

Testing model binding in Backbone JS with Jasmine

I have a view that contains a model. The view listens for an event from the model and will perform an action once the event is triggered. Below is my code
window.Category = Backbone.Model.extend({})
window.notesDialog = Backbone.View.extend({
initialize: function() {
this.model.bind("notesFetched", this.showNotes, this);
},
showNotes: function(notes) {
//do stuffs here
}
})
I want to test this using Jasmine and below is my test (which doesn't work)
it("should show notes", function() {
var category = new Category;
var notes_dialog = new NotesDialog({model: category})
spyOn(notes_dialog, "showNotes");
category.trigger("notesFetched", "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})
Does anyone know why the above test doesn't work? The error I get is "Expected spy showNotes to have been called with [ '[]' ] but it was never called."
I was doing something similar where I had a view, but I couldn't get the spy to work properly unless I added it to the prototype, and before I created the instance of the view.
Here's what eventually worked for me:
view.js
view = Backbone.View.extend({
initialize: function(){
this.collection.bind("change", this.onChange, this);
},
...
onChange: function(){
console.log("Called...");
}
});
jasmine_spec.js
describe("Test Event", function(){
it("Should spy on change event", function(){
var spy = spyOn(view.prototype, 'onChange').andCallThrough()
var v = new view( {collection: some_collection });
// Trigger the change event
some_collection.set();
expect(spy).toHaveBeenCalled()
});
});
I would test initially with the toHaveBeenCalled() expectation and change to the toHaveBeenCalledWith() after you get that working...
Update 5/6/2013: Changed update() to set()
Try to amend your existing test code as follows:
it("should show notes", function() {
var category = new Category;
spyOn(NotesDialog.prototype, "showNotes");
var notes_dialog = new NotesDialog({model: category})
category.trigger("notesFetched", "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})
In your original code, the instance of the method you are calling is one defined in the bind closure, whereas the one you are spying on is in the notes_dialog instance. By moving the spy to the prototype, you are replacing it before the bind takes place, and therefore the bind closure encapsulates the spy, not the original method.
Using a spy means to replace the function you spying on. So in your case you replace the bind function with the spy, so the internal logic of the original spy will not call anymore. And thats the right way to go cause you dont wanna test that Backbones bind is work but that you have called bind with the specific paramaters "notesFetched", this.showNotes, this.
So how to test this. As you know every spy has the toHaveBeenCalledWith(arguments) method. In your case it should looks like this:
expect(category.bind).toHaveBeenCalledWith("notesFetched", category. showNotes, showNotes)
So how to test that trigger the "notesFetched" on the model will call your showNotes function.
Every spy saves the all parameters he was called with. You can access the last one with mostRecentCall.args.
category.bind.mostRecentCall.args[1].call(category.bind.mostRecentCall.args[2], "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
mostRecentCall.args[1] is the the second argument in your bind call (this.showNotes). mostRecentCall.args[2] is the the third argument in your bind call (this).
As we have test that bind was called with your public method showNotes, you can also call the your public method showNotes directly, but sometimes the passed arguments can access from outside so you will use the shown way.
Your code looks fine, except do you have the test wrapped in a describe function, as well as an it function?
describe("show notes", function(){
it("should show notes", function(){
// ... everything you already have here
});
});
Total guess at this point, but since you're not showing the describe function that's all I can think it would be. You must have a describe block for the tests to work, if you don't have one.
You are pretty close ;)
spyOn replaces the function with your spy and returns you the spy.
So if you do:
var dialog_spy = spyOn(notes_dialog, "showNotes");
category.trigger("notesFetched", "[]");
expect(dialog_spy).toHaveBeenCalledWith("[]");
should work just fine!