this.own not defined in Dojo - javascript

I'm trying to create a singleton class in Dojo with a method called loadsth. There I want o run this.own from within a foreach loop. However, when I run this code it says
TypeError: this.own is not a function
I looked into the Dojo docs and scripts and there it says that the method "own" is part of dijit/Destroyable. But although it is included it doesn't work. I tried it at the positions //#1 and //#2. I actually need it at position //#2 but wanted to make sure that the foreach loop doesn't hide "this". So I tried //#1 but this doesn't work as well.
define([
"dojo/_base/declare",
"dijit/Destroyable"
], function (
declare,
destroyable
) {
var SingletonClass = declare("some.Class", null, {
_registerdPropertyGrids: [],
_resourceNode: "",
/*
* This method is used register a property grid plus
* provide the properties that should be shown in that
* grid.
*/
registerWidget: function(widgetName, propertyGridWidget) {
console.log(widgetName);
this._registerdPropertyGrids.push({widgetName, propertyGridWidget});
},
/*
* Sets the resource node for this widget.
*/
setResourceNode: function(resourceNode) {
this._resourceNode = resourceNode;
},
/*
* Loads sth.
*/
loadSth: function() {
console.log("load");
//var deferred = this.own(...)[0]; // #1
this._registerdPropertyGrids.forEach(function(element, index, array) {
console.log('_registerdPropertyGrids[' + index + '] = ' + element.widgetName);
var deferred = this.own(...)[0]; // #2
}, this);
}
});
if (!_instance) {
var _instance = new SingletonClass();
}
return _instance;
});
I suppose it has something todo with the implementation of the single class.
So my actual question is: Why does it say that this.own is not defined when I have dijit/Destroyable in the dependency list of "define"?

You have dijit/Destroyable listed as a dependency but you're not actually making your declared constructor extend from it, and as a result your own prototype doesn't have own on it.
Instead of declare("...", null, {, you want declare(destroyable, { (where destroyable is replacing null).
Notes:
The string argument to declare is deprecated, as it populates a global namespace, which is discouraged with AMD.
I would recommend renaming destroyable to Destroyable. Common convention is for constructors to start with a capital letter.

Related

How to update a variable that depends on another variable in a function?

In the sample code below, note that the value of the variable dependent depends on the variable prereq. When the function changePrereq is called, it changes the value of prereq. This change is shown if logged, but it isn't reflected in the value of dependent. Instead, when dependent is put into a span, it shows Some text - undefined.
How can I have dependent change depending on the value of prereq?
P.S. Thanks everyone for the advice. For myself, I chose the answer from "ztcollazo" as the right decision.
"outis" - Thank you for your explanations. I will definitely pay attention to your recommendations and study them in more detail!
var display = document.getElementById('text'),
prereq,
message = "Some text - " + prereq;
function updateDisplay() {
display.innerHTML = message;
console.log(prereq);
}
function changePrereq() {
prereq = "I am some text.";
updateDisplay();
}
<p><span id="text"></span></p>
<button onclick="changePrereq()">Click</button>
The problem is that changeMyText doesn't update when someText does. You need to define changeMyText inside of the changeTextFunc function and then pass someText as a parameter.
Example:
var myText = document.getElementById('text');
var someText1;
var m1 = 1;
function changeTextFunc(someText, m) {
var changeMyText = "Some text - " + someText;
if (m > 0) {
myText.innerHTML = changeMyText;
} else {
console.log('m < 0');
}
}
function changeText() {
someText1 = "I a'm some text.";
changeTextFunc(someText1, m1);
}
<div>
<button onclick="changeText()">Click</button>
<p id="text"></p>
</div>
move changeMyText variable into changeTextFunc function.
the code will looks like this
function changeMyText(m){
var changeMyText = "Some text - " + someText1;
if (m > 0) {
myText.innerHTML = changeMyText;
} else {
console.log('m < 0');
}
}
If you want a variable to change based on another, you must set its value after the other is changed. There are various approaches, with various implementations. You can break it down into different aspects for the change:
what:
globals (note: avoid global variables in production, and use sparingly in other contexts for the practice)
locals
objects
plain methods
getter/setter methods
where:
inline, at the site a variable is referred to
in a separate function created for the responsibility
when:
the prerequisite variable is changed
the dependent variable is used
Some of the above options from different aspects aren't intended to be combined, or can't be combined. For example, 1.3 (objects) is intended to go with 2.2 (separate functions), and 1.3.2 (getters/setters) requires 2.2, since object getters & setters are functions (2.2 basically means "use a getter or setter", though not necessarily using getter/setter syntax). You might be able to think of other aspects, or other possibilities for the above aspects.
ztcollazo shows a solution that uses a global for the prerequisite (1.1), a local for the dependent (1.2) and updates inline (2.1) when the dependent is used (3.2). If the line in changeTextFunc setting changeMyText were instead move to changeText (and a global used), you'd have 1.1 + 2.1 + 3.1.
For some more example implementations, examine the following. It illustrates four different options from the above, noted by comments.
var display = document.getElementById('output'),
dependent, prereq;
/* options 1.1, 2.2, 3.1: global, separate function, prereq change */
function setPrereq(value) {
prereq = value;
dependent = "global prereq setter: " + prereq;
}
function updateDisplayFromVariable() {
display.innerText = dependent;
}
function changePrereq_updateWhenSet(value="setter") {
setPrereq(value);
updateDisplayFromVariable();
}
/* options 1.1, 2.2, 3.2: global, separate function, dependent used */
function getDependent(value) {
return dependent = "global dependent getter: " + prereq;
}
function updateDisplayFromGetter() {
display.innerText = getDependent();
}
function changePrereq_updateWhenUsed(value="inline, no setter") {
prereq = value;
updateDisplayFromGetter();
}
/* options 1.3.2, 2.2: (local) object getter/setter */
/* wrapped in self-called function to prevent polluting global namespace */
var dependency = (function () {
let display = document.getElementById('output'),
/* options 1.3.2, 2.2, 3.2: (local) object getter, dependent used */
inGetter = {
prereq: 'initial',
/* note: `dependent` is entirely synthetic */
get dependent() {
return "object's dependent getter: " + this.prereq;
},
},
/* options 1.3.2, 2.2, 3.1: (local) object setter, prereq changed */
inSetter = {
/* note: when using setter, can't use same name for the
* backing property; instead, must also define getter. */
_prereq: 'initial',
get prereq() {
return this._prereq;
},
set prereq(value) {
this._prereq = value;
this.dependent = "object's prereq setter: " + value;
},
};
function updateDisplay(from) {
display.innerText = from.dependent;
}
/* expose 1.3.2, 2.2, 3.1 */
function whenSet(value) {
inSetter.prereq = value;
updateDisplay(inSetter);
}
/* expose 1.3.2, 2.2, 3.2 */
function whenUsed(value) {
inGetter.prereq = value;
updateDisplay(inGetter);
}
return {whenSet, whenUsed};
})();
<button onclick="changePrereq_updateWhenSet('thimbles')">Use global setter</button>
<button onclick="changePrereq_updateWhenUsed('care')">Use global getter</button>
<button onclick="dependency.whenSet('forks')">Use object setter</button>
<button onclick="dependency.whenUsed('hope')">Use object getter</button>
<p><span id="output"></span></p>
As with any design, the above have advantages and disadvantages, but using object setters/getters (1.3.2) should be preferred, as it's the most robust approach. Using standalone functions (not getters/setters) and updating inline are both more brittle as a programmer may fail to use them somewhere, instead assigning & referencing variables directly. Updating inline is also less maintainable, as any changes will have to be made on every line that performs the update. Global variables have their own issues, such as:
limited code reuse in a module (note how updateDisplay(from) works for two different cases, whereas changePrereq_updateWhenSet and changePrereq_updateWhenUsed each require different display functions), and
inflexibility (i.e. composing existing functions for new behaviors is much more limited; in other words, this limits code reuse for client code),
naming collisions when different modules use the same globals, causing them to stomp on each other.
As for whether to update the dependent in the prerequisite's setter (1.3.2 + 2.2 + 3.1) or to use a getter for the dependent with no backing property (in some circles, this is known as a "synthetic property") depends on other requirements (basically, whether the dependent be allowed to be assigned values independent of the prerequisite). You could, for instance, use getters & setters for both properties.

Referencing a parent object in callback functions with jQuery

I've a page that is generated dynamically, and that includes certain number (user-dynamically-defined) of advanced scatter plot charts. I intend to create a JavaScript object which defines the scatter plot itself, i.e. which takes some parameters, some data, and some container ID, and which will create the various elements needed to obtain the visualisation: canvas elements, toolbar, etc.. To do so, I started with the following (simplified) class:
(function () {
if (!this.namespace) { this.namespace = {};}
this._instances = { index: 0 };
this.namespace.ScatterPlot = function (containerId, file, options) {
_instances.index ++;
this.id = this.containerId+"-"+_instances.index ;
this.containerId = containerId ;
_instances [this.id] = this;
// ... Do stuffs with file and options ...
// Initialize elements once the DOM is ready
$(this.updateDOM);
}
namespace.ScatterPlot.prototype = {
updateDOM: function() {
$("<canvas>")
.click(clickCallback)
.appendTo("#"+this.containerId);
//(...)
},
clickCallback: function() {
alert("Some click: "+this.id);
}
}
})();
Each object can be created with:
var v1 = new namespace.ScatterPlot("container1", "foo", "foo");
var v2 = new namespace.ScatterPlot("container2", "foo", "foo");
There are two problems here: (1) in updateDOM, 'this' does not make reference to my initial ScatterPlot object, which means that this example will never work, and (2) similarly, the clickCallback will not be able reference the scatterplot with 'this' either.
I'm new to javascript, and I'm still struggeling to understand the logic of OO programming in javascript, so the question is: I'm I taking the wrong direction here ? After some digging, I could roughly achieve what I wanted by passing this to updateDOM:
$(this.updateDOM(this)); // This blows my eyes but does the trick, at least partially
updateDOM: function(that) {
$("<canvas>")
.click(that.clickCallback)
.appendTo("#"+that.containerId);
//(...)
},
clickCallback: function() {
// Not working either... Should pass 'that' to the function too
alert("Some click: "+this.id);
}
But I don't feel this patters to be very elegant... And the problem is not fixed either regarding the click callback.
Thoughts ?
Have a look at MDN's introduction to the this keyword.
The standard ways of dealing with that issue are using a that variable - not as an argument, but in a separate function:
var that = this;
$(function() {
that.updateDOM();
});
// or
$(this.getClickCallback());
...
namespace.ScatterPlot.prototype.getClickCallback = function() {
var that = this;
return function clickCallback(e) {
alert("Some click: "+that.id);
};
};
Alternatively, you can always use .bind() (or $.proxy for older browsers) which do quite what the second example does in a more generic way:
$(this.clickCallback.bind(this));

Unable to create a new instance of a Backbone View

I have a "master" view, a layout if you will, that loads other views through the loadView method. My problem is that these view classes perform some initialisation logic (in initialize) that can only be performed once (to do with templating). If, however, I try and instantiate these classes more than once, I get an error symptomatic of calling initialize on the same instance.
I have tried, in the console, instantiating them separately by loading the class and creating two new instances using var x = new MyViewClass(); but each time the first one instantiates and the second one fails because of this error caused by the templates already being initialised.
This really shouldn't be happening, but I cannot for the life of me see what is causing the problem.
The layout's loading code is below.
loadView: function(name, bootstrap_function) {
this.unloadView();
var _class = require('View/'+name), // Let's load the view file
pretty = name.replace('/', ''), // Prettify the name by removing slashes (should end up with some camelcased niceness)
bs_name = '__bootstrap'+pretty, // Generate the name of the bootstrap function
view = new _class(); // Pass the event aggregator in
// If there is a bootstrap function, bootstrap
if(typeOf(bootstrap_function) == 'function') { // Check if one has been passed in
bootstrap_function.call(this, view); // Bootstrap: function(AppView, LoadedView)
}
this._loaded = view; // Store the view in _loaded
// Now that we have a view to play with
// we should insert it into our container object
view.$el.appendTo(this.$container);
// And render!
view.render();
},
unloadView: function() {
if(this._loaded !== null) {
this._loaded.remove();
this._loaded.unbind();
this._loaded = null;
}
}
EDIT
The templating code that is having the errors is this:
processTemplates: function() {
if(this.templates === undefined) return this;
console.log(this.templates);
if(Object.getLength(this.templates) > 0) {
Object.each(this.templates, function(template, name) {
this.templates[name] = _.template(template);
}, this);
}
return this;
},
The console.log(this.templates) output shows that on the first initialisation, this.templates contains strings, as it should, but on second initialisation it shows template functions (which should only be the case after processTemplates() is called.
I wonder if it could have anything to do with the way my class is defined, for example:
define(
['backbone', 'View/Kords', 'text!Template/Pages/Landing.html', 'Collection/TenantTypes'],
function(Backbone, KordsView, landing_html, TenantTypesCollection) {
var LandingView = KordsView.extend({
tagName: 'div',
className: 'tiled-light',
templates: {
'main': landing_html
},
landing_html is defined like this in the class, but could there be a reference problem? _.template should not be affecting the value of landing_html within the scope, should it?
EDIT #2
It is not to do with the reference to landing_html. I tried just setting templates.main to a string in the class definition but I still got the errors as before.

Troubles Writing A Proper jQuery Plugin

I'm in the process of rewriting a jQuery plugin to be used in an RSS reader I'm building during an internship. This plugin uses Google's Feed API to pull a JSON-formatted RSS feed and return it to the developer, allowing them fine-tuned control over how that feed is displayed on the webpage. I have been following the official jQuery Plugin Authoring page as a reference.
On the reference page, code examples say that you need to add your plugin to jQuery's prototype: $.fn. Here's what I've done:
(function($) {
"use strict";
$.fn.rssObj = function(newUrl) {
var RSSFeed = function(newUrl) {
/*
* An object to encapsulate a Google Feed API request.
*/
this.feedUrl = newUrl;
};
RSSFeed.prototype.load = function() {
var feed = new google.feeds.Feed(this.feedUrl);
feed.load(function(result) {
console.log(result);
});
};
return new RSSFeed(newUrl);
};
})(jQuery);
When I attempt to use this plugin by executing $.rssObj("http://rss.test.com"), my browser gives me this error:
$.rssObj() is not a function
What am I doing wrong?
You add to $.fn if you want your function to be available on jQuery instances (e.g., the objects you get back from $("your selector here") and such). If you want your function available from the $ object directly, you add it directly to it.
Here's an example showing each:
// Creating the plugin
(function($) {
// This will be on *instances*
$.fn.green = function() {
// `this` is the jQuery instance we were called on
return this.css("color", "green");
};
// This will be on the $/jQuery object itself
$.blue = function(selector) {
// You don't use `this` here (you could if you want,
// it will be === $/jQuery, but there's no reason to)
$(selector).css("color", "blue");
return this;
};
})(jQuery);
// Usage
jQuery(function($) {
// Make all divs green with a border
$("div").green().css("border", "1px solid green");
// Make all paragraphs blue
$.blue("p");
});
<div>I'm a div</div>
<p>I'm a paragraph</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
See where I've done exactly what the author was wanting to do here! I simply used this template I've been using for years:
(function($) {
if (!$.myExample) { // check your plugin namespace does not already exist
$.extend({ // this will allow you to add your plugin to the jQuery lib
myExample: function(elm, command, args) {
// keep in mind, right here you might want to do a class or data check to determine which direction this call is going
// for example, upon init the plugin on an element you may add the plugin name as a class,
// this way, when it's recalled, you can see it alrady has that class and might be calling a command,
// thus make an if statemnt to push the process through
return elm.each(function(index){
// do work to each element as its passed through
// be sure to use something like
// return elm.each(function(e) { dor work });
// as your final statement in order to maintain "chainability"
});
}
});
$.fn.extend({ // this gives the chainability functionality seen with $ funcs like: $("#eleID").css("color", "red") <--returns original element object
myExample: function(command) {
return $.myExample($(this), command, Array.prototype.slice.call(arguments, 1));
}
});
$.myExample.props = { // Here you can establish specific properties to your plugin, prehaps even make them "Over-writable"
key1: "value",
key2: "value"
};
$.myExample.methods = { // Here you can establish specific methods/functions for your plguin to carry out and maintain your namespace as well
key1: function(param) {
/* do work */
},
key2: function(param) {
/* do work */
}
};
// This next part is not seen in many plugins but useful depending on what you're creating
$.myExample.init = function(param) { // If you have an initialize method to apply, namespace it in here and calll on initializing your plugin
var key = "value",
key2 = {
subKey: "value"
};
/*
/ run any number of initializing functions here
/ I prefer to make my param a value that can be a
/ string with a possible object
/ the string for holding a base configuration
/ the object for any change in properties or base values for that config
*/
};
$.myExample.defaults = { // establish base properties here that can be over-written via .props, but their values should never truly change
key1: "value",
key2: {
prop1: {
subKey1: "value",
subKey2: "value"
},
prop2: {
subKey1: "value"
}
},
key3: function(param) {
}
};
}
})(jQuery);

Creating methods on the fly

Hi I'm trying to author a jQuery plugin and I need to have methods accessible to elements after they are initialized as that kind of object, e.g.:
$('.list').list({some options}); //This initializes .list as a list
//now I want it to have certain methods like:
$('.list').find('List item'); //does some logic that I need
I tried with
$.fn.list = function (options) {
return this.each(function() {
// some code here
this.find = function(test) {
//function logic
}
}
}
and several other different attempts, I just can't figure out how to do it.
EDIT:
I'll try to explain this better.
I'm trying to turn a table into a list, basically like a list on a computer with column headers and sortable items and everything inbetween. You initiate the table with a command like
$(this).list({
data: [{id: 1, name:'My First List Item', date:'2010/06/26'}, {id:2, name:'Second', date:'2010/05/20'}]
});
.list will make the <tbody> sortable and do a few other initial tasks, then add the following methods to the element:
.findItem(condition) will allow you to find a certain item by a condition (like findItem('name == "Second"')
.list(condition) will list all items that match a given condition
.sort(key) will sort all items by a given key
etc.
What's the best way to go about doing this?
If you want these methods to be available on any jQuery object, you will have to add each one of them to jQuery's prototype. The reason is every time you call $(".list") a fresh new object is created, and any methods you attached to a previous such object will get lost.
Assign each method to jQuery's prototype as:
jQuery.fn.extend({
list: function() { .. },
findItem: function() { .. },
sort: function() { .. }
});
The list method here is special as it can be invoked on two occasions. First, when initializing the list, and second when finding particular items by a condition. You would have to differentiate between these two cases somehow - either by argument type, or some other parameter.
You can also use the data API to throw an exception if these methods are called for an object that has not been initialized with the list plugin. When ('xyz').list({ .. }) is first called, store some state variable in the data cache for that object. When any of the other methods - "list", "findItem", or "sort" are later invoked, check if the object contains that state variable in its data cache.
A better approach would be to namespace your plugin so that list() will return the extended object. The three extended methods can be called on its return value. The interface would be like:
$('selector').list({ ... });
$('selector').list().findOne(..);
$('selector').list().findAll(..);
$('selector').list().sort();
Or save a reference to the returned object the first time, and call methods on it directly.
var myList = $('selector').list({ ... });
myList.findOne(..);
myList.findAll(..);
myList.sort();
I found this solution here:
http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html
This seems to do exactly what I need.
(function($) {
var TaskList = function(element, options)
{
var $elem = $(element);
var options = $.extend({
tasks: [],
folders: []
}, options || {});
this.changed = false;
this.selected = {};
$elem.sortable({
revert: true,
opacity: 0.5
});
this.findTask = function(test, look) {
var results = [];
for (var i = 0,l = options.tasks.length; i < l; i++)
{
var t = options['tasks'][i];
if (eval(test))
{
results.push(options.tasks[i]);
}
}
return results;
}
var debug = function(msg) {
if (window.console) {
console.log(msg);
}
}
}
$.fn.taskList = function(options)
{
return this.each(function() {
var element = $(this);
if (element.data('taskList')) { return; }
var taskList = new TaskList(this, options);
element.data('taskList', taskList);
});
}
})(jQuery);
Then I have
$('.task-list-table').taskList({
tasks: eval('(<?php echo mysql_real_escape_string(json_encode($tasks)); ?>)'),
folders: eval('(<?php echo mysql_real_escape_string(json_encode($folders)); ?>)')
});
var taskList = $('.task-list-table').data('taskList');
and I can use taskList.findTask(condition);
And since the constructor has $elem I can also edit the jQuery instance for methods like list(condition) etc. This works perfectly.
this.each isn't needed. This should do:
$.fn.list = function (options) {
this.find = function(test) {
//function logic
};
return this;
};
Note that you'd be overwriting jQuery's native find method, and doing so isn't recommended.
Also, for what it's worth, I don't think this is a good idea. jQuery instances are assumed to only have methods inherited from jQuery's prototype object, and as such I feel what you want to do would not be consistent with the generally accepted jQuery-plugin behaviour -- i.e. return the this object (the jQuery instance) unchanged.

Categories

Resources