I'd love to get my hands on a templates data context.
Can I do something like this?
'click .newContext': function(event, template) {
var template_parent = template.parent();
var parent_data = template_parent.data;
}
You can use Template.parentData(0), the argument defines how deep you want to go, if you pass none, 0 is the default. Check the documentation on this: http://docs.meteor.com/#/full/template_currentdata
Yeah, if you're trying to get the parent's data context you should be able to use the parentData() method on the Template instance. You probably don't even need that second template parameter.
'click .newContext': function(event) {
var parent_data = Template.parentData();
}
Related
I extend a Control to create a new custom control in UI5 and this control renders a tree as UL items nicely. Now I need to implement a collapse/expand within that tree. Hence my renderer writes a tag like
<a class="json-toggle" onclick="_ontoggle"></a>
and within that _ontoggle function I will handle the collapse/expand logic.
No matter where I place the _ontoggle function in the control, I get the error "Uncaught ReferenceError: _ontoggle is not defined"
I am missing something obvious but I can't find what it is.
At the moment I have placed a function inside the
return Control.extend("mycontrol",
{_onToggle: function(event) {},
...
Please note that this event is not one the control should expose as new event. It is purely for the internals of how the control reacts to a click event.
I read things about bind and the such but nothing that made sense for this use case.
Took me a few days to crack that, hence would like to provide you with a few pointers.
There are obviously many ways to do that, but I wanted to make that as standard as possible.
The best suggestion I found was to use the ui5 Dialog control as sample. It consists of internal buttons and hence is similar to my requirement: Render something that does something on click.
https://github.com/SAP/openui5/blob/master/src/sap.ui.commons/src/sap/ui/commons/Dialog.js
In short, the solution is
1) The
<a class="json-toggle" href></a>
should not have an onclick. Neither in the tag nor by adding such via jQuery.
2) The control's javascript code should look like:
sap.ui.define(
[ 'sap/ui/core/Control' ],
function(Control) {
var control = Control.extend(
"com.controlname",
{
metadata : {
...
},
renderer : function(oRm, oControl) {
...
},
init : function() {
var libraryPath = jQuery.sap.getModulePath("mylib");
jQuery.sap.includeStyleSheet(libraryPath + "/MyControl.css");
},
onAfterRendering : function(arguments) {
if (sap.ui.core.Control.prototype.onAfterRendering) {
sap.ui.core.Control.prototype.onAfterRendering.apply(this, arguments);
}
},
});
control.prototype.onclick = function (oEvent) {
var target = oEvent.target;
return false;
};
return control;
});
Nothing in the init(), nothing in the onAfterRendering(), renderer() outputs the html. So far there is nothing special.
The only thing related with the onClick is the control.prototype.onclick. The variable "target" is the html tag that was clicked.
I'm trying to use Backbone with REST API:
Here the code
My model:
var PagesModel = Backbone.Model.extend({
idAttribute: 'Guid',
initialize: function () {
this.on('remove', this.destroy);
},
urlRoot: '/api/pages'
});
Collection:
var PagesCollection = Backbone.Collection.extend({
model: PagesModel,
url: '/api/pages'
});
View:
var PagesView = Backbone.View.extend({
el: '#pages',
events: {
'click .removePage': 'remove',
},
initialize: function (collection) {
this.collection = collection;
this.collection.fetch();
this.template = $('#pages-template').html();
this.collection.bind('change reset', this.render, this);
},
render: function () {
var template = _.template(this.template);
$(this.el).html(template({ pages: this.collection.toJSON() }));
return this;
},
remove: function (e) {
e.preventDefault();
var id = $(e.currentTarget).closest('ul').data("id");
var item = this.collection.get(id);
this.collection.remove(item);
$(e.currentTarget).closest('ul').fadeOut(300, function () {
$(this).remove();
});
}
});
And here I'm starting up application:
$(function () {
var pagesCollection = new PagesCollection();
var pagesView = new PagesView(pagesCollection);
});
I'm clicking or Remove and in Network inspector see this link
http://localhost:54286/backbone/function%20()%20%7B%20%20%20%20%20%20var%20base%20=%20getValue(this,%20'urlRoot')%20%7C%7C%20getValue(this.collection,%20'url')%20%7C%7C%20urlError();%20%20%20%20%20%20if%20(this.isNew())%20return%20base;%20%20%20%20%20%20return%20base%20+%20(base.charAt(base.length%20-%201)%20==%20'/'%20?%20''%20:%20'/')%20+%20encodeURIComponent(this.id);%20%20%20%20}
instead of /api/pages/{guid}.
What I'm doing wrong?
I still haven't figured fully why, but you can make it work by destroying your model after the end of its removal (Backbone does one last thing after triggering the remove event: destroy the collection's reference in the model).
But what's even better, is using directly the destroy function on the model, it will remove it from the collection automatically (use {wait: true} if needed).
Edit:
Finally managed to locate the source of the problem. It's rather simple in fact. To override the model's url (calculated with urlRoot but that doesn't matter), you can pass Model#destroy a url option when calling Backbone.sync (or something that'll call it).
Now you're thinking "but I don't!". But you do. The listener (Model#destroy in your case) is given 3 arguments. Model#destroy will take the first one (the model itself) as options.
And here's the fail (I think Backbone needs a patch to this): giving an url option to Backbone.sync is the only time _.result in not used to calculate the url. So you find yourself having as url the url property of your model, which is the function you see in your call.
Now, for a quickfix:
this.on('remove', this.destroy.bind(this, {}));
This will ensure the first argument of your Model#destroy call is {} (as well as binding the context).
Bear with me a little longer.
Now, if you're still willing to call Collection#remove before destroying your model, here's a little hack: because (as I stated above) the remove event is triggered before Backbone makes sure to remove the collection's reference in your model, you don't need the urlRoot property in your model. Indeed, the model won't be in the collection anymore, but Backbone will still take the collection's url into account to get the model's url (as the reference is still there).
Not a definitive answer, but just going by the code in your question and the backbone.js documentation, the problem may be that you named your method remove and this is getting in the way of the remove method in Backbone.View.
http://backbonejs.org/#View-remove
Update:
It also looks like the output you see in the network inspector is that the definition of the Backbone.Model.url function is being appended. Meaning url is not being properly called (Maybe the () is missing by the caller?). Are you overriding Backbone.sync anywhere in your application?
I am using x-editable for in-line editing inside my web app. I would like to pass additional parameters to server, which I would like to read from data- attributes on trigger element. Here is my editable element:
Value
I would like to pass data-param attribute, but I don't know how to access trigger element. I tried via $(this).data('param'), but I get null... My full editable code:
$.fn.editable.defaults.mode = 'inline';
$('.editable').editable({
params: { param: $(this).data('param') }
});
Calling $('.editable').data('param') doesn't come into account since I have many .editable elements present.
Thanks
I figured it out. I'm answering in case somebody needs to know:
$('.editable').editable({
params: function(params) {
// add additional params from data-attributes of trigger element
params.param1 = $(this).editable().data('param');
params.param2 = $(this).editable().data('nextparam');
return params;
}
)
I apologize if this has been asked before but, is there a way to add an event listener/handler to a Javascript object? Preferably using JQuery.
Such as:
var foo;
$(foo).bind('change', function() {
alert("Foo has changed!");
});
I have tried this, but nothing seems to happen. Does this only work with DOM elements?
EDIT:
I need an event fired every time that the audio or video tags throw an error. Originally, I was using an interval to check whether or not the error, 'media.error', object was null, but this uses excess processing power and I would like to avoid it.
EDIT 2: Apparently I was going about it wrong, easiest way I found was to add the "onerror" property to the video/audio tag.
I agree with Cheeso that it's more important for you to state what you actually want to do, however one workaround for your specific question could be to store your variable within an object and only provide access through getter / setter, then you can do what you want in the setter. e.g.
function data() {
var foo = 0;
this.setFoo = function(newVal) {
foo = newVal;
alert(foo);
};
}
var theData = new data();
theData.setFoo(5);
Yes, that's correct. You cannot make a "variable watcher". There is no event fired for variables when they are changed.
What are you really trying to do?
You could try:
http://higginsforpresident.net/js/static/jq.pubsub.js
See
http://weblog.bocoup.com/publishsubscribe-with-jquery-custom-events
Or use a framework like backbone/underscore or knockout.js.
HTML/Elements/audio
var foo;
$(foo).bind('error', function() {
//your code here
});
How do you keep track of your UI elements in Titanium? Say you have a window with a TableView that has some Switches (on/off) in it and you'd like to reference the changed switch onchange with a generic event listener. There's the property event.source, but you still don't really know what field of a form was just toggled, you just have a reference to the element. Is there a way to give the element an ID, as you would with a radiobutton in JavaScript?
Up to now, registered each form UI element in a dictionary, and saved all the values at once, looping through the dictionary and getting each object value. But now I'd like to do this onchange, and I can't find any other way to do it than create a specific callback function for each element (which I'd really rather not).
just assign and id to the element... all of these other solution CAN work, but they seem to be over kill for what you are asking for.
// create switch with id
var switcher0 = Ti.Ui.createSwitch({id:"switch1"});
then inside your event listener
myform.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "switch1" ) {
// do some magic!!
}
});
A simple solution is to use a framework that helps you keep track of all your elements, which speeds up development quite a bit, as the project and app grows. I've built a framework of my own called Adamantium.js, which lets you use a syntax like jQuery to deal with your elements, based on ID and type selectors. In a coming release, it will also support for something like classes, that can be arbitrarily added or removed from an element, tracking of master/slave relationships and basic filter methods, to help you narrow your query. Most methods are chainable, so building apps with rich interaction is quick and simple.
A quick demo:
// Type selector, selects all switches
$(':Switch')
// Bind a callback to the change event on all switches
// This callback is also inherited by all new switch elements
$(':Switch').bind('change', function (e) {
alert(e.type + ' fired on ' + e.source.id + ', value = ' + e.value);
});
// Select by ID and trigger an event
$('#MyCustomSwitch').trigger('change', {
foo: 'bar'
});
Then there's a lot of other cool methods in the framework, that are all designed to speed up development and modeled after the familiar ways of jQuery, more about that in the original blog post.
I completely understand not wanting to write a listener to each one because that is very time consuming. I had the same problem that you did and solved it like so.
var switches = [];
function createSwitch(i) {
switches[i] = Ti.UI.createSwitch();
switches[i].addEventListener('change', function(e) {
Ti.API.info('switch '+i+' = '+e.value);
});
return switches[i];
}
for(i=0;i<rows.length;i++) {
row = Ti.UI.createTableViewRow();
row.add(createSwitch(i));
}
However keep in mind that this solution may not fit your needs as it did mine. For me it was good because each time I created a switch it added a listener to it dynamically then I could simply get the e.source.parent of the switch to interact with whatever I needed.
module Id just for the hold it's ID. When we have use id the call any another space just use . and use easily.
Try This
var but1 = Ti.Ui.createButton({title : 'Button', id:"1"});
window.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "1" ) {
// do some magic!!
}
});
window.add(but1);
I, think this is supported for you.
how do you create your tableview and your switcher? usually i would define a eventListener function while creating the switcher.
// first switch
var switcher0 = Ti.Ui.createSwitch();
switch0.addEventListener('change',function(e){});
myTableViewRow.add(switch0);
myTableView.add(myTableViewRow);
// second switch
var switch1 = ..
so no generic event listener is needed.