Javascript error: $(...).observe is not a function - javascript

I'm trying to use Stitch onEvent mixin in Tapestry 5.3.7.
Here's the OnEvent Javascript from there:
T5.extendInitializers({
onEvent: function (spec) {
var element = $(spec.id).observe(spec.event, function () {
var params = {};
if (spec.fieldIds) {
for (var i = 0; i < spec.fieldIds.length; ++i) {
var fieldId = spec.fieldIds[i];
var paramName = "onEvent." + fieldId;
var paramValue = $(fieldId).getValue();
params[paramName] = paramValue;
}
}
var zoneManager = Tapestry.findZoneManagerForZone(spec.zone);
zoneManager.updateFromURL(spec.url, params);
});
}
});
I use it in my TML like this:
<t:form t:id="filterTextForm">
<div style="float:right">
<input id="filterText" t:id="filterText" t:type="textfield"
t:value="filter" zone="configZone" t:autofocus="literal:true" onClick="this.select()" t:mixins="onEvent" event="keyup"/>
</div>
</t:form>
and my event method like this:
void onKeyupFromFilterText(String filter) {
this.filter = filter;
if (request.isXHR()) {
ajaxResponseRenderer.addRender(configZone).addRender(descZone);
}
}
When I have t:mixins="onEvent" event="keyup", none of the zones are updating on the page, no AJAX requests are generated.
When I remove it, everything works fine, except the part I'm trying to do, described in my question.
I'm using Tapestry 5.3.7.

observe() is a prototype function. I'm guessing that you're using tapestry-jquery which is a 3rd party library that removes prototype and replaces it with jquery.
You'll need to adapt the javascript to work with jquery (eg observe() needs to change to on())
You might find other bits of js broken too (eg I'm not sure if tapestry-jquery's ZoneManager is exactly the same as core tapestry).
tapestry-jquery comes with a builtin bind mixin which does a similar job to onevent. You might find it sufficient to use this mixin instead.

Related

Select2: Tags not working properly with custom DataAdapter

I am using a custom dataAdapter and also trying to use the 'tags' attribute in Select2 jQuery plugin. But the exemple found in the documentation is not working at all, the 'tags' attribute is simply ignored (this is only happening when using a custom dataAdapter, otherwise it's working fine).
So this is not working:
$(".js-example-tags").select2({
tags: true
});
As a solution for this, I've found out we can use a decorator for Tags in the dataAdapter, and it really works! Problem is, it will always work. So if I have two 'select' tags in HTML, and I want one of them to have 'tags:true' and the other one to have 'tags:false', they'll both have tagging enabled because of this decorator. I've tried setting 'tags:false', but it's not working.
I'm thinking a solution would be in the dataAdapter, to create an if statement for the decorator, for it to be applied or not. But then the problem is that this specific code is executed only once, when the first 'select' is created.
So I'm thinking that if I use a dataAdapter for creating multiple selects, all of them will have the same decorators. And I don't think having multiple dataAdapters would be a solution for me.
So my question is, if I have multiple 'select' elements, how can I use different decorators applied for each of them? Also using the same dataAdapter?
I also have a JSFiddle for this:
Tags with dataAdapter
Thanks!
We have just run into this as well and I have been unable to find anything on how to "correctly" implement this. Feel there is a pattern or hook I'm missing that select2 should provide here.
I've come up with 2 ways of handling this.
1. Handle adding the decorators up front of calling select2
(function ($) {
var CustomDataAdapter = $.fn.select2.amd.require('select2/data/customDataAdapter');
var Utils = $.fn.select2.amd.require('select2/utils');
var Tags = $.fn.select2.amd.require('select2/data/tags');
var MinimumInputLength = $.fn.select2.amd.require('select2/data/minimumInputLength');
$.fn.mySelect2 = function(options) {
if (!options.dataAdapter && options.customDataAdapterOptions) {
options.dataAdapter = CustomDataAdapter;
if (options.minimumInputLength > 0) {
options.dataAdapter = Utils.Decorate(options.dataAdapter, MinimumInputLength);
}
if (options.tags) {
options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
}
}
return this.select2(options);
};
}(jQuery));
Usage changes to: $('selector').mySelect2(options);
2. Override the Defaults.apply method that handles this for built in dataAdapters
(function() {
var CustomDataAdapter = $.fn.select2.amd.require('select2/data/customDataAdapter');
var Utils = $.fn.select2.amd.require('select2/utils');
var Tags = $.fn.select2.amd.require('select2/data/tags');
var MinimumInputLength = $.fn.select2.amd.require('select2/data/minimumInputLength');
var baseApply = $.fn.select2.defaults.apply;
$.fn.select2.defaults.apply = function (options) {
if (!options.dataAdapter && options.customDataAdapterOptions) {
options.dataAdapter = CustomDataAdapter;
if (options.minimumInputLength > 0) {
options.dataAdapter = Utils.Decorate(options.dataAdapter, MinimumInputLength);
}
if (options.tags) {
options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
}
}
return baseApply.apply(this, arguments);
};
}());
Usage does not change: $('selector').select2(options);

How do I set up a class structure in Google Apps Script?

This seems like a very basic question. But how do I create a class structure within Google Apps Script?
Lets say I want to call: myLibrary.Statistics.StandardDeviation(). I have to instead call: myLibrary.StandardDeviation().
I cannot seem to break it down any further, or organize it into classes.
How can I do this?
I suspect there's something more that you're not telling us about your situation. It is possible to set up a function as a property of an object that is itself a property of an object, and thus support the calling structure you've described.
function test() {
Logger.log( myLibrary.Statistics.StandardDeviation([5.3,5.2,5,2.0,3.4,6,8.0]) ); // 1.76021798279042
};
myLibrary.gs
var myLibrary = {};
myLibrary.Statistics = {}
myLibrary.Statistics.StandardDeviation = function( array ) {
// adapted from http://stackoverflow.com/a/32201390/1677912
var i,j,total = 0, mean = 0, diffSqredArr = [];
for(i=0;i<array.length;i+=1){
total+=array[i];
}
mean = total/array.length;
for(j=0;j<array.length;j+=1){
diffSqredArr.push(Math.pow((array[j]-mean),2));
}
return (Math.sqrt(diffSqredArr.reduce(function(firstEl, nextEl){
return firstEl + nextEl;
})/array.length));
}

Create a Reusable HTML Control w/ Javascript

So, I've been searching through some existing questions dealing with re-usable items in HTML and Javascript, and I'm not sure if there's anything that gives me the start I'm looking for. I'm not super well-versed in js, but rather than re-write the same code over and over again and have to perform the upkeep on it, I'd prefer to build a re-usable framework that I can apply in several places.
The basic layout is this: There's an input field with an "Add" button, each time you add a name, it displays below the input with a checkbox. When you uncheck it, the name is removed from the list.
I'm fine with styling and building the HTML, what I'm lost on is developing an object in js that I can apply in multiple places. What I had in mind was this:
function createInputControl(targetElementId) {
var newInputControl = new ItemInputControl();
newInputControl.onItemAdded = customItemAddedCallback;
newInputControl.onItemRemoved = customItemRemovedCallback;
newInputControl.createInElement(targetElementId);
}
That's the start I'm looking for. An object that I can create that has designated callbacks for when an item is added or removed via user interaction, and a way for me to draw it within an existing element on my page.
EDIT: What I'm looking for here is a skeleton of a javascript object (named ItemInputControl above) with these functions / properties that I can re-use throughout my site.
Ok, so If I understand you correctly - you're looking for help on how to make a globally accessible variable that can be used in your entire application, like jQuery. You have two main options for what you are looking to do
First - you could use an Object Literal, which exposes a single global variable and all of your methods are contained within:
(function (window) {
var inputControl = {
onItemAdded: function () {
// do stuff
},
onItemRemoved: function () {
// do stuff
},
createInElement: function (targetElementId) {
// do stuff
}
};
window.ItemInputControl = inputControl;
})(window);
This is used like so:
ItemInputControl.createInElement("elementId");
Your second option is to use Prototype:
(function (window) {
var inputControl = function () {
// Constructor logic
return this;
};
inputControl.prototype.onItemAdded = function () {
// do stuff
return this;
};
inputControl.prototype.onItemRemoved = function () {
// do stuff
return this;
};
inputControl.prototype.createInElement = function (elementId) {
// do stuff
return this;
};
window.ItemInputControl = inputControl;
})(window);
This would be used like so:
var newInputControl = new ItemInputControl();
newInputControl.createInElement("elementId");
For most cases in individual applications - I prefer to use Object Literals for my framework. If I were building a widely distributed javascript framework, I would probably use a prototype pattern. You can read more on prototype patters here: http://www.htmlgoodies.com/beyond/javascript/some-javascript-object-prototyping-patterns.html
Well, I'm not sure if this is exactly helpful, but perhaps it will contain a few ideas for you.
The two HTML elements needed are stored as format strings, and everything is dynamically added/removed in the DOM.
var listid = 0;
$(document).ready(function() {
var controlHtml = + // {0} = mainid
'<div>' +
'<input id="text-{0}" type="text" />' +
'<div id="add-{0}" class="addButton">Add</div>' +
'</div>' +
'<div id="list-{0}"></div>';
var listHtml = + // {0} = mainid, {1} = listid, {2} = suplied name
'<div id="list-{0}-{1}"><input id="checkbox-{0}-{1}" type="checkbox class="checkboxClass" checked />{2}<div>';
$('#content').append(controlHtml.f('0'));
$('.addButton').click(function(e) { addClick(e); });
});
function addClick(e) {
var id = e.currentTarget.id.split('-')[1];
var name = $('text-' + id).val();
$('.list-' + id).append(listHtml.f(id, listid, name));
listid++;
$('.checkboxClass').click(function() { checkboxClick(e); });
}
function checkboxClick(e) {
$('#' + e.currentTarget.id).remove();
}
String.prototype.f = function () { var args = arguments; return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; }); };
And of course very minimal HTML to allow a hook for adding your control:
<body>
<div id="content"></div>
</body>

How to get the name of a jQuery UI widget?

I need a way to read the name of a jQuery UI widget. I have subclassed the dialog widget into two subclasses, myDialog1 and myDialog2. I have created a destroyDialog function to destroy whichever dialog is active. There should be a way to determine the name of the widget instance.
What I want to do is something like this:
var destroyDialog = function() {
activeDialog[activeDialog.widgetName]("destroy");
}
But I don't see a way to get the widget name. For now I'm using ugly nested try-catch statements.
var destroyDialog = function() {
try {
activeDialog.dialog("destroy");
}
catch (e) {
try {
activeDialog.myDialog1("destroy");
}
catch (e) {
activeDialog.myDialog2("destroy");
}
}
}
You can get the widget name (and use it) by using
activeDialog.data("widgetName");
... as tdmartin refers to. So therefore:
activeDialog[activeDialog.data("widgetName")]("destroy");
But to get around this problem personally, I have written a plugin that will allow you to call a widget method without knowing what type the widget is. This will allow you to do:
activeDialog.callWidgetMethod('destroy');
It relies on you using jQuery UI 1.11+. If you are using <1.11, you can take out the "Skip this widget if it does not have the method" check, but the downside of that is that you will get an error if you attempt to call a method that a widget does not have.
Plugin code:
jQuery.fn.callWidgetMethod = function () {
var args = arguments;
var result = null;
if(!this || !this.length)
return this;
this.each(function (i,o) {
var compClass = $(this).data("widgetName");
var func = $(this)[compClass];
// Skip this element if it does not appear to be an initialised jQuery widget
if(!compClass || !func)
return true;
// Skip this widget if it does not have the method (the name of which will be in args[0])
// This relies on the 'instance' method provided in jQuery UI 1.11
if(args.length>1 && !$(this)[compClass]("instance")[args[0]])
return true;
result = func.apply($(this),args);
});
if(this.length>1)
return this;
else
return result;
};
If you standardize your namespace you could use a regex to match the name of the variable where your widget instance is stored (the name of the widget), returned by the $().data() method.
for (i in $(<your element>).data() ) {
if (i.match(/dialog/)) {
$(<your element>).data(i).destroy();
}
}

How do I create methods for an HTML element?

I'm trying to create a simple, small and basic javascript framework just for learning purposes.
But the thing is that i'm allready stuck at the very basics.
I'm trying to do something like this:
$('testdiv').testFunction();
And the code i've written for that:
var elementID;
var smallFramework = {
$:function(id) {
this.elementID = id;
},
testFunction:function() {
alert(this.elementID);
}
};
window.$ = smallFramework.$;
But in return I get:
$('testdiv) is undefined
Can anyone help me with this small and hopefully easy question?
To get the behavior you're expecting, you need the $ function to return an object with a method named testFunction.
Try:
var smallFramework = // an object for namespacing
{
$:function(id) // the core function - returns an object wrapping the id
{
return { // return an object literal
elementID: id, // holding the id passed in
testFunction: function() // and a simple method
{
alert(this.elementID);
}
};
}
};
Of course, there are many other ways to achieve the behavior you desire.
If you're trying to add methods to an HTML element you could do something along these lines.
$ = function( elementId ) {
var element = document.getElementById( elementId );
element.testFunction = function(){
alert( this.id );
return this; // for chaining
}
return element;
}
$('test').testFunction();
Try
smallFramework.$('testdiv');
instead. According to the code you posted, that's where your $ function ended up.
Or alternatively, it looks like you're trying to replicate something like jQuery. You might want to try something like this.
var $ = smallFramework = (function () {
var f =
{
find:function(id) {
f.elementID = id;
return f; //every function should return f, for chaining to work
},
testFunction:function() {
alert(f.elementID);
return f;
}
}
return f.find //the find function will be assigned to $.
//and also assigned to smallFramework.
//the find function returns f, so you get access to testFunction via chaining
// like $("blah").testFunction()
})() //note this function gets called immediately.
this code may look confusing to someone new to JavaScript because it depends heavily on the concept of closures. I suggest that if this doesn't make sense, spend some time at Douglas Crockford's JavaScript website. This is important because the code above will bite if you happen to use this in the find function because this won't be bound to f, as you may expect it to be when you use it from $ or smallFramework.

Categories

Resources