I am new to Backbone and am wondering something.
I've seen some tutorial where the user uses this code to explain an event.
var ImageModel = Backbone.Model.extend({ initialize: function(){
this.on('change',this.someChange,this); //when some property in this object has changed, run this.someChange() function },
defaults : { title : 'untitled',
description : 'no description available',
owner : 'anonymous',
date : 'no date supplied' },
someChange: function(model,options){ alert(‘something has changed’);
}
});
var photo = new ImageModel({title:’awesome image’}); //create new instance
photo.set(‘title’,’really awesome indeed’); //change the title attribute, this will trigger ‘change’ event
photo.set({title:’well i agree’},{agree: ‘yep’}); //alternative way to change model attribute with optional option passed, this will also trigger change event. </p>
And In some other examples I've seen people usings triggers to activate the event.
Eg
`var object = {};
_.extend(object, Backbone.Events); object.on("alert", function(msg) {
alert("Triggered " + msg); });
object.trigger("alert", "an event");
My questions is how do the first example use the event 'change' when it doesn't get trigged in anyway. It doesn't use 'change' anywhere in the code. I know that it uses the function someChange but how does it now to "activate" when the event isn't trigged or "used" in the code.
If you're not understanding the question I am sorry. Not sure how to explain the problem.
I think you need to spend a little time reading the Backbone documentation (shouldn't take you more than 1 hour). There is a list of predefined events you will be using a lot when writing Backbone applications: "change", "reset", and so on.
http://backbonejs.org/#Events-catalog
Regarding your particular example, Backbone.Events is the component used inside Backbone to provide any object/class with event emitting functionality. Backbone.Model of course includes Backbone.Events.
Your first snippet shows how to listen to a Backbone.Model change event to do something, while the second mixes the Backbone.Events into a JS object to be able to trigger from it.
That's the beauty of Backbone, the same methods (on, off, listenTo) are used in Models, Views, Collections, because they all inherit Backbone.Events. Once you grasp it, it's all rock and roll. :)
Related
I've started discovering and using FullCalendar but I'm stuck with it.
What I want to do is a ResourceTimeline in Month view, with external event dragging (a left panel).
The subject later would be to have a modal when you drop an event, in order to choose if you want the event to be from 8am to 12pm, or afternoon from 12pm to 6pm.
So first, I'd like to do a simple eventReceive without modal, to see if I can update the event when it's dropped.
But it seems I can't, what do I do wrong ?
From what I can understand, it looks like when you drop an event in month view, the event in the param sent to eventReceive is modified.
eventReceive(info) {
info.event.start = moment(info.event.start).add(8, 'hours').format('YYYY-MM-DD hh:mm:ss');
// var c = confirm('OK = morning, Cancel = aprem');
// if (c) {
// console.log("morning !")
// } else {
// console.log("afternoon !")
// }
}
Events are very basic because I wanted to complete them whenever I drop them into the calendar
new Draggable(listofEvents, {
itemSelector: '.draggable',
eventData(event) {
return {
title: event.innerText,
activite: event.dataset.activite,
allDayDefault: false,
}
},
})
I even tried to force allDayDefault to false but it doesn't change a thing...
Here is the codepen of the project in its current state : https://codepen.io/nurovek/pen/zYYWGyX?editors=1000
Sorry if my post lacks information, I'm not used to ask questions on SO. If it's lacking, I'll try to be more explicit if you ask me, of course !
As per the documentation, an event's public properties (such as "start", "end", title" etc) are read-only. Therefore to alter a property after the event is created you must run one of the "set" methods.
So your idea will work if you use the setDates method:
eventReceive(info) {
info.event.setDates(moment(info.event.start).add(8, 'hours').toDate(), info.event.end, { "allDay": false } )
console.log(info.event);
}
Demo: https://codepen.io/ADyson82/pen/dyymawy?editors=1000
P.S. You might notice I also made a few other little changes to your CodePen, mainly to correct all the links to CSS and JS files, since it was generating all sorts of console errors. These errors were because links were wrong or simply referred to something non-existent, and for some reason you were also using files from two different versions of fullCalendar (4.3.0 and 4.3.1), which is never a good idea if you want to ensure full compatibility.
I have an existing Quick Action button on an object, which I would like to display as a button for Community Users
I have tried implementing lightning:quickActionAPI in a Lightning Component that I created, then added the component to the record detail page in Community Builder. I have changed the actual names of objects and fields with general names
<lightning:quickActionAPI aura:id="quickActionAPI" />
<lightning:button label="Update" onclick="{!c.updateRequestStatus }" />
updateRequestStatus : function(component, event, helper) {
//debugger;
var actionAPI = component.find("quickActionAPI");
var fields = {fieldApiName: {value:"Closed"}};
var args = {actionName: "objectApiName.quickActionName", entityName: "objectApiName", targetFields: fields};
actionAPI.setActionFieldValues(args).then(function(){
actionAPI.invokeAction(args);
}).catch(function(e){
console.error(e.errors);
});
}
Expected result: when clicking on the button in the community, the quick action will be called and a window will open
Actual result: clicking on the button executes the JS method but nothing happens
I'm currently seeing the same thing in my Community. The documentation says lightning:quickActionAPI is only available in Lightning Experience, and makes no references to Communities. I don't think it's supported, yet. Though it is confusing that the actionAPI object will instantiate just fine in a Community context but its promises never complete.
I am learning backbone.js. I found the following code from backbone.js documentation.
//cretaing class name as Sidebar with extends Backbone.Model class
var Sidebar = Backbone.Model.extend({
promptColor:function() {
var cssColor = prompt("Please enter a CSS color:");
this.set({color1: cssColor});
}
});
//cretaing object for Sidebar class
var sidebarObject = new Sidebar();
//following statement not understand
sidebarObject.on("change:color1", function(model, color23) {
$('#body1').css({background: color23})
});
What I understand :
whenever attribute color1 will change automatically model('Slidebar') triggers sidebarObject.on().
What I didn't understand :
we are passing 2 arguments names are model,color23 to second argument of the sidebarObject.on(). I didn't understand anything about that arguments.
2.As per my understanding model is Sidebar in my example.Is it right.
can anyone help me.
Thanks.
Yes, your second assumption is correct, in the above example Sidebar is the Model.
There are 2 parameters being passed to the callback function:
the model on which the event initially occurred
the value being passed alongside with the event
Note that the sidebarObject listens only to 'color' change events. Such event is generated when you change that particular attribute of the model:
this.set({color1: cssColor});
Now, if you change the listener to:
sidebarObject.on("change:taste", function(model, color23) {
$('#body1').css({background: color23})
});
it won't be fire anymore when this.set({color: cssColor}); is called, because it listens to 'taste' change:
this.set({taste: 'good'});
I've separated the above example into a fiddle so you can play with it: http://jsfiddle.net/CtzsR/1/
If you are new to this whole thing http://backbonetutorials.com/what-is-a-model/ is a site worth looking at.
I hope now it's clearer.
I'm trying to register my onClick listener to dijit Button placed as in-cell widget withing GridX. I've done the following, basing on example test_grid_cellWidget:
{ field: "save", name:"Save",
widgetsInCell: true,
navigable: true,
decorator: function(){
//Generate cell widget template string
return '<button data-dojo-type="dijit.form.Button" data-dojo-attach-point="btn">Save</button>'
},
setCellValue: function(data){
//"this" is the cell widget
this.btn.set("label", "Speichern")
this.btn.connect("onClick", function(){
alert('clicked')
})
}
},
setCellValue is executed successfully, and the label is changed. However, the onClick listener is not registered and is not called, when I click on button. When I use the syntax data-dojo-props="onClick:function" it works, but it requires declaring listener function as global, which is something I'd like to avoid.
Anyway, I have the Button object, and I'm executing the code found in dijit documents, so it should be working. But why nothing is registered in that context?
I've found the answer in GridX wiki: https://github.com/oria/gridx/wiki/How-to-show-widgets-in-gridx-cells%3F
You need to use the field cellWidget.btn._cnnt:
setCellValue: function(gridData, storeData, cellWidget){
this.btn.set("label", "Speichern")
if(cellWidget.btn._cnnt){
// Remove previously connected events to avoid memory leak.
cellWidget.btn._cnnt.remove();
}
cellWidget.btn._cnnt = dojo.connect(cellWidget.btn, 'onClick', lang.hitch(cellWidget.cell, function(){
rowSaveClick(this.row)
}));
},
I don't know what dojo version you use, but as you use data-dojo-type, I suppose it's 1.7+.
First, I would recommend to drop the dot notation of module names and start using the AMD mid syntax instead (i.e.: drop "dijit.form.Button" for "dijit/form/Button", as the dot notation will be dropped in dojo 2.0).
Then, the recommended way of connecting events to widgets is to :
either define the event as a function (like widget.onClick = function(evt){...})
or use the "on" method of the widget (like widget.on("click", function(evt){...}))
I prefer to use the second form, as it's more consistent with dojo/on. It consists of using the event name without the "on", and put everything in lowercase. For example, if your widget had an extension point named "onMouseRightClick", you could use it as widget.on("mouserightclick", ...)
Your example would then become :
{ field: "save", name:"Save",
widgetsInCell: true,
navigable: true,
decorator: function(){
//Generate cell widget template string
return '<button data-dojo-type="dijit/form/Button" data-dojo-attach-point="btn">Save</button>'
},
setCellValue: function(data){
//"this" is the cell widget
this.btn.set("label", "Speichern")
this.btn.on("click", function(){
alert('clicked')
});
}
},
Note : untested code. I'm just guessing what the problem might be. Let me know if there is still an issue...
I've found that using getCellWidgetConnects works quite well (see docs).
But the docs aren't exactly clear, so it wasn't working for me at first. If you are connecting to a DomNode, the pass 'click' as the event in the connections array. If you are connecting to a Dijit widget, then pass 'onClick'.
I may be completely missing something here, but I have the following:
a Model which encapsulates 'all' the data (all JSON loaded from one URL)
the model has one (or more) Collections which it is instantiating with the data it got on construction
some code which I want to run on the Collection when the data is initialized and loaded
My question is about the composed Collection. I could do this outside the scope of the Collection, but I'd rather encapsulate it (otherwise what's the point of making it a 'class' with an initializer etc).
I thought I could put that code in the initialize() function, but that runs before the model has been populated, so I don't have access to the models that comprise the collection (this.models is empty).
Then I thought I could bind to an event, but no events are triggered after initialization. They would be if I loaded the Collection with a fetch from its own endpoint, but I'm not doing that, I'm initializing the collection from pre-existing data.
My question: How to get initialize code to run on the Collection immediately after it is initialized with data (i.e. this.models isn't empty).
Is it possible to do this without having to get 'external' code involved?
Okay here is the demo code, perhaps this will explain things better.
var Everything = Backbone.Model.extend({
url: "/static/data/mydata.json",
parse: function(data)
{
this.set("things", new Things(data.things, {controller: this}));
}
});
var Thing = Backbone.Model.extend({
});
var Things = Backbone.Collection.extend({
model: Thing,
initialize: function(data, options)
{
// HERE I want access to this.models.
// Unfortunately it has not yet been populated.
console.log("initialize");
console.log(this.models);
// result: []
// And this event never gets triggered either!
this.on("all", function(eventType)
{
console.log("Some kind of event happend!", eventType);
});
}
});
var everything = new Everything();
everything.fetch();
// Some manual poking to prove that the demo code above works:
// Run after everything has happened, to prove collection does get created with data
setTimeout(function(){console.log("outside data", everything.get("things").models);}, 1000);
// This has the expected result, prints a load of models.
// Prove that the event hander works.
setTimeout(function(){console.log("outside trigger", everything.get("things").trigger("change"));}, 1000);
// This triggers the event callback.
Unfortunately for you the collection gets set with data only after it was properly initialized first and models are reset using silent: true flag which means the event won't trigger.
If you really wanted to use it you can cheat it a bit by delaying execution of whatever you want to do to next browser event loop using setTimeout(..., 0) or the underscore defer method.
initialize: function(data, options) {
_.defer(_.bind(this.doSomething, this));
},
doSomething: function() {
// now the models are going to be available
}
Digging this an old question. I had a similar problem, and got some help to create this solution:
By extending the set function we can know when the collection's data has been converted to real models. (Set gets called from .add and .reset, which means it is called during the core function instantiating the Collection class AND from fetch, regardless of reset or set in the fetch options. A dive into the backbone annotated source and following the function flow helped here)
This way we can have control over when / how we get notified without hacking the execution flow.
var MyCollection = Backbone.Collection.extend({
url: "http://private-a2993-test958.apiary-mock.com/notes",
initialize: function () {
this.listenToOnce(this, 'set', this.onInitialized)
},
onInitialized:function(){
console.log("collection models have been initialized:",this.models )
},
set: function(models,options){
Backbone.Collection.prototype.set.call(this, models, options);
this.trigger("set");
}
})
//Works with Fetch!
var fetchCollection= new MyCollection()
fetchCollection.fetch();
//Works with initializing data
var colData = new MyCollection([
{id:5, name:'five'},
{id:6, name:'six'},
{id:7, name:'seven'},
{id:8, name:'eight'}
])
//doesn't trigger the initialized function
colData.add(new Backbone.Model({id:9,name:'nine'};
Note: If we dont use .listenToOnce, then we will also get onInitialized called every time a model is added to or changed in the collection as well.