Getting method not defined error using dojo lang.hitch - dojo

I'm pretty new to dojo, and I'm trying to use the lang.hitch method to handle my callbacks, but I keep getting an "Uncaught Reference Error: is not defined error" when using it. I'm sure I'm doing something wrong - I'm just not sure what it is. this refers to my newly created object in the initializeLocators function, verified as I stepped through my code. The candidates parameter to the showResults method is returned from the event handling closure. Thanks for your help.
My class:
define(["dojo/_base/declare", ..., "dojo/_base/lang", "dojo/on", "dojo/dom", ...],
function(declare, ..., lang, ...){
var SDCLocateClass = declare(null, {
...,
constructor: function() {
this.initializeLocators();
},
initializeLocators: function() {
this.addressNode = dom.byId("resultsDiv");
//set up the address locator functionality
this.locator = new Locator("http://...");
this.locator.on("address-to-locations-complete", lang.hitch(this, showResults));
},
showResults: function(candidates) {
...
},
});
return SDCLocateClass;
});

showResults is a variable that is not defined. Use this.showResults or use a string "showResults"
this.locator.on("address-to-locations-complete",
lang.hitch(this, this.showResults));

Related

Why does variable substitution not work for my case?

I'm trying to create a custom widget using templates, but variable substitution does not seem to be working for me.
I can see the property value being updated inside the widget, but the DOM does not change. For example, when I use the get() method, I can see the new value of the widget's property. However, the DOM never changes its value.
Here is my template:
<div class="outerContainer">
<div class="container">
<span class="mySpan">My name is ${name}</span>
</div>
</div>
Now, here is my widget code:
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dojo/text!/templates/template.html",
], function (declare, _WidgetBase, _TemplatedMixin, template) {
return declare([_WidgetBase, _TemplatedMixin], {
templateString: template,
name: "",
constructor: function (args) {
console.log("calling constructor of the widget");
this.name = args.name;
},
startup: function() {
this.inherited(arguments);
this.set("name", "Robert"); // this does not work
},
postCreate: function() {
this.inherited(arguments);
this.set("name, "Robert"); // this does not work either
},
_setNameAttr: function(newName) {
// I see this printed in the console.
console.log("Setting name to " + newName);
this._set("name", newName);
// I also see the correct value when I get()
console.log(this.get("name")); // This prints Robert
}
});
});
I was expecting the DOM node to say "My name is Robert" i.e. the new value, but it never updates. Instead, it reads "My name is ". It does not overwrite the default value.
I'm sure I'm missing a silly step somewhere, but can someone help me figure out what?
You should bind the property to that point in the dom. So you will need to change the template to this:
<span class="mySpan">My name is <span data-dojo-attach-point='nameNode'></span></span>
And in your widget you should add this function to bind it whenever name changes:
_setNameAttr: { node: "nameNode", type: "innerHTML" },
Now when name changes, it will change the innerHTML of the nameNode inside your mySpan span. If you need to know more about this binding I recommend checking the docs out.
Hope this helps!

vue js returned value gives undefined error

i want to check the returned value of $http.get() but i get undefined value. Here is my vue js code:
var vm = new Vue({
el: '#permissionMgt',
data: {
permissionID: []
},
methods:{
fetchPermissionDetail: function (id) {
this.$http.get('../api/getComplaintPermission/' + id, function (data) {
this.permissionID = data.permissionID; //permissionID is a data field of the database
alert(this.permissionID); //*****this alert is giving me undefined value
});
},
}
});
Can you tell me thats the problem here?.. btw $http.get() is properly fetching all the data.
You need to check what type is the data returned from the server. If #Raj's solution didn't resolve your issue then probably permissionID is not present in the data that is returned.
Do a colsole.log(data) and check whether data is an object or an array of objects.
Cheers!
Its a common js error. Make the following changes and it will work.
fetchPermissionDetail: function (id) {
var self = this; //add this line
this.$http.get('../api/getComplaintPermission/' + id, function (data) {
self.permissionID = data.permissionID; //replace "this" with "self"
});
},
}
the reason is this points to window inside the anonymous function function()
This is a well known js problem. If you are using es2015 you can use arrow syntax (() => { /*code*/ }) syntax which sets this correctly

DataTable().ajax.reload() not defined

I have the following code under DT v1.10:
var oTable = $('#items')
.dataTable({
sDom: "<'row'<'col-md-4'l><'col-md-6'f>r>t<'row'<'col-md-4'i><'col-md-7'p>>",
oLanguage: {
sLengthMenu: "_MENU_ per page"
},
ajax: "/items",
bProcessing: true,
bServerSide: true,
aoColumnDefs: [
{
aTargets: [-1],
bSearchable: false,
bSortable: false
}
]
})
.on('click', '.btn-danger', function (e) {
if (confirm('Are you sure you want to delete SKU "' + $(this).data('sku') + '"?')) {
$.getJSON($(this).attr('href'), function (data) {
if ('success' in data) {
oTable.ajax.reload(null, false);
}
});
}
event.stopPropagation();
return false;
});
When the server responds with success, it tries to call the line oTable.ajax.reload(null, false); but I always get the error Uncaught TypeError: Cannot read property 'reload' of undefined
What am I doing wrong here?
You're using old API: $().dataTable() (v1.9 and earlier) which is still available in DataTables v1.10. The old API returns jQuery object, so you should use .api() in order to use DataTable API methods:
oTable.api().ajax.reload();
The new API is returned via: $().DataTable()
Datatables FAQ
Q.: I get an error message stating that an API method is not available
A.: Very likely you are using a jQuery object rather than a DataTables API instance. The form $().dataTable() will return a jQuery object, while $().DataTable() returns a DataTables API instance. Please see the API documentation for further information.
API documentation
It is important to note the difference between $( selector ).DataTable() and $( selector ).dataTable(). The former returns a DataTables API instance, while the latter returns a jQueryJS object. An api() method is added to the jQuery object so you can easily access the API, but the jQuery object can be useful for manipulating the table node, as you would with any other jQuery instance (such as using addClass(), etc.).
As a follow up to phillip100's answer, you dont have to change all your old code, or change the initialization method just to use the new API. You can always get the dataTables 1.10.x API on the fly :
...
if ('success' in data) {
//oTable.ajax.reload(null, false);
$('#items').DataTable().ajax.reload(null, false);
}
...
Would be perfectly well too. jQuery dataTables check if there already is a dataTables instance of $("#items"), so there will be no redundancy.

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?

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!