understanding dojo hitch with parameters - dojo

I am trying to understand the below dojo code, but couldn't, can someone help me on this
lang.hitch({"window": window, mysource: lang.clone(sourcename)}, function (myst) {})

Dojo hitch set the value of this in your callback function.
lang.hitch({"window": window, mysource: lang.clone(sourcename)}, function (myst) {
//this will equal {"window": window, mysource: lang.clone(sourcename)}
console.log(this);
});
Its the same as using javascripts bind or call function.
function(myst){
//this will be assigned ObjectToBind
console.log(this);
}.bind(ObjectToBind)

Related

How to hook into a change in the model in a widget

I'm trying to respond to a change in one of the properties of the model in a widget. To be clear, when the value of the property changes, I want to run some code to react to the change. In a parent widget I have a date picker which changes the date in the model.
I cannot get the custom setter to be called _setParentPropertyAttr...
If I include this in my widget
<span data-dojo-type="dojox/mvc/Output" data-dojo-props="value: at(rel:, 'ParentProperty')">
It works nicely. Changing the date picker outputs the current value to the page. So I can supply the value property to the output widget when the date changes in the model. But what I need to do (I think) is supply a custom property with the date property in the model when the date picker changes the value.
I realise this question is a bit vague but I can't provide the code as it's proprietary.
I've tried to break the problem down by setting a property manually within my widget as:
myProperty:0,
...
constructor
...
_setMyPropertyAttr: function(value):
{
console.log("setting myproperty");
}
....
this.set('myProperty', 5);
....
but that isn't working either.
If you set a property within a widget does that not call the custom setter?
I'm struggling a bit because there aren't so many dojo examples out there any help is much appreciated.
You can bind an event to be called when a widget's property is set/update or you can even use watch to do that.
But this only works using the set function, using someWidget.someProperty = 5; wont work.
Let me show you how dojo do it. The basic about the magic setters and getters is explained here.
_set: function(/*String*/ name, /*anything*/ value){
// summary:
// Helper function to set new value for specified property, and call handlers
// registered with watch() if the value has changed.
var oldValue = this[name];
this[name] = value;
if(this._created && !isEqual(oldValue, value)){
if(this._watchCallbacks){
this._watchCallbacks(name, oldValue, value);
}
this.emit("attrmodified-" + name, {
detail: {
prevValue: oldValue,
newValue: value
}
});
}
}
This peace of code is from dijit/_WidgetBase, the _set function is what dojo calls after a set is called, and is where it finally set the property value this[name] = value; and as you can see, it emit an event that will be called attrmodified-propertyName and also call a watchCallbacks.
For example, if in some place, we have this:
on(someWidget, 'attrmodified-myproperty', function(){
console.log(someWidget.get('myProperty'));
});
and then we use:
someWidget.set('myProperty', 'Hello World!');
The event will be triggered. Note that someWidget.myProperty = 'Hello World!' wont trigger the event registration. Also note that if in our widget we define the magic setter:
_setMyPropertyAttr: function(value) {
//do something here with value
// do more or less with other logic
//but some where within this function we need to cal "_set"
this._set('myProperty', value);
}
without calling _set, the magic wont happen.
As i said at the beginning, we can also use watch:
someWidget.watch('myProperty', function(){
console.log(someWidget.get('myProperty'));
});
Note that we can register to this events or the watch function within the same widget.
Also, as a plus, the magic setter can be triggered when creating the widget with just passing the property name in the constructor object param, this work for the declarative syntax too, for example:
var someWidget = new MyWidget({
'myProperty': 'Hello World!!'
});
and
<div data-dojo-type="MyWidget" data-dojo-props="myProperty: 'Hello World!!'"></div>
both will triggered a call to the _setMyPropertyAttr if exist, or dojo will use the magic setter in the case it doesn't exist.
Hope it helps
Consider using custom setter on your widget, where you can add your custom logic.
Example of definition of custom setter on your widget:
_setOpenAttr: function(/*Boolean*/ open){
// execute some custom logic here
this._set("open", open);
}
Example of setting a property on your widget:
widgetRef.set('open', true);
Alternatively you can could consider using dojo/store/Observable.
dojo/store/Observable store wrapper that adds support for notification of data changes.
You can read more about it on the followign link:
https://dojotoolkit.org/reference-guide/1.10/dojo/store/Observable.html
If figured out the problem. If I set a watch on the model I can then check if indiviual properties have changed in the watch function. I knew it would be something simple!

How can I hide a dijit/form/button?

I think it is a common sense that providing a simple way to hide/show and enable/disable a button, but I cannot find any document that describe dojo has done such thing.
Any way, I hope it is my fault that I have missed out something while googling, thanks!
The following coding is what I have tried but they just make the button's text invisible:
dojo.style(btnInsert, {'visibility':'hidden'});
dojo.style(btnInsert, {'display':'none'});
UPDATE Question:
To oborden2:
I have tried your code, the result is same as the above code, here is the captured screen:
To MiBrock:
I have also tried your code and also get the result that same as the above code:
Form widgets in Dijit are special. For all normal Dijit widgets, the domNode (outermost node) of the widget receives the id property. However, with form widgets, the focusNode (which corresponds to the <input> element) receives the ID instead, so that things like <label for="foo"> work properly. In this case, the outermost node has no ID, and you’re actually just hiding the inner HTML input element.
If you already have reference to the widget:
require([ 'dojo/dom-style' ], function (domStyle) {
domStyle.set(widget.domNode, 'display', 'none');
});
If you only have a reference to the ID of the widget/original DOM node:
require([ 'dojo/dom-style', 'dijit/registry' ], function (domStyle, registry) {
domStyle.set(registry.byId(nodeId).domNode, 'display', 'none');
});
Try
require(["dojo/dom-style","dojo/domReady!"], function(domStyle){
domStyle.set(dojo.byId(domNode),'display','none');
});
The variable "domNode" stays for the id of the Node that should be influenced. This is the way we make it.
Regards, Miriam
Try using the Toggler module
require(["dojo/fx/Toggler"], function(Toggler),{
// Create a new Toggler with default options
var toggler = new Toggler({
node: "btnInsert"
});
// Hide the node
toggler.hide();
// Show the node
toggler.show();
});
http://dojotoolkit.org/reference-guide/1.9/dojo/fx/Toggler.html
I imagine you would want to link this to some event using Dojo's on module. Link it up to whatever condition triggers the button's need to be hidden.

How to use dojox/mobile/ScrollablePane Events

ScrollablePane in dojo mobile have some event that we can use as they have mentioned in their API documentation. I try to use the as follows.
leftPane.on("onTouchEnd", function(e){
alert("sss");
});
(leftPane is a ScrollablePane) This does not work. But this works when I use a event like "click". I search throughout the net for a example but didn't find a one. Can someone help me out here.
Thank you.
use:
aspect.after(leftPane, 'onTouchEnd', function(e) { });
dojo/on is tricky when it comes to the event naming - you could start by ditching the "on" prefix. Most likely, simply changing onTouchEnd to touchend would work
The Dojo event system changed significantly between 1.6 and 1.7. The new on function and the Evented mixin is the recommended way of handling events in widgets, but there are some backward-compatibility functions in the _WidgetBase class.
In short, you can either use the legacy dojo.connect function, the new aspect function (which implementes the "connect to normal javascript method" functionality of the old dojo.connect), or use the new on method in the _WidgetBase class that is a bridge between the two.
1. dojo.connect(leftPane, 'onTouchEnd', function(e) { });
2. aspect.after(leftPane, 'onTouchEnd', function(e) { }, true); // <-- the 'true' is important!
3. leftPane.on('touchend', function(e) { });
YMMV on (3) depending on whether the widget was updated to provide this bridging.

jQuery: execute function on matched elements returned via Ajax

This jQuery selector matches a Rails 3 HTML form for a new model: $('form[id^="new_"]')
I'd like to have a simple focus function run each time a matching form loads. Sometimes the forms are loaded via a simple GET but also via Ajax. In the latter case, the content returned can be either HTML or escaped JS.
I was hoping jQuery would be able to match all cases via the selector, .on(), and the "load" event, but I can't seem to make that work for ANY case. Code:
$(document).ready(function() {
$('form[id^="new_"]').on("load", function(){
console.log("Matched!")
});
})
Any ideas?
Thanks Justice. I'm afraid I wasn't able to get your code to work. I'm using the following callback with the new custom event defined outside it as shown and I don't think the $('form') is triggering the event.
$('.shows-children').bind('ajax:success', function(evnt, data, status, xhr){
var boxSelector = '#' + $(this).data("shows");
$(boxSelector).html(xhr.responseText);
$('form').trigger('customevent');
});
$(document).on('customevent','form[id^="new_"]', function(){
console.log('Matched!')
});
(I'm surprised it seems more involved than expected to have jQuery act on HTML returned in an Ajax response.)
$(document).on("change","form[id^=\"new_\"]" function(){
console.log("Matched!")
});
For delegation, you want to delegate the original selector to a parent, as the event will bubble up.
However, load does NOT bubble up. In this case, change may suffice, but it'll trigger and attempt to see if the delegate is valid every time the document changes.
I would then suggest that you create a custom event after AJAX loads for the form.
Example:
$(document).on("customevent","form[id^="new_"]" function(){
console.log("Matched!")
$.ajax(url, function(response){
//success
$(document).append(response);
$('form').trigger('customevent');
});
});
HTH

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!