In working with Titanium's Alloy framework, the models are using Backbone.js. I'm new to both Backbone.js and Alloy.
I'm familiar with ExtJS however, and in ExtJS, you can create a form, and then say something like:
form.loadRecord(record); // where record is an instance of a model
and then
form.getRecord(record); // When you're saving the form, get the record
var vals = form.getValues(); // And then get the values from the form that the user changed
record.setValues(vals); // Update your record with whatever values the user changed.
So my question is, what is the pattern for forms in Alloy? Or is there not one?
I could easily make my own functions, however I'm running into an issue where the app crashes when trying to bind a model to a form object like this:
that.model = model; // where model was passed in to the form.loadRecord function.
Related
I am currently trying to implement the Model-View-Controller in my SAPUI5 / Fiori Project.
I managed to create an Instance of the Controller with: new sap.ui.core.mvc.Controller('controller.js')
This does not work for the Model (sap.ui.core.mvc does not contain a Model attribute).
Now I am searching a way to call functions of the Model from the Controller, to get my data.
I already tried this code: oObjModel = new sap.ui.mode.Model(), using this I cannot call functions from my Model.
I recommend you look at the walkthrough on the SAPUI5 documentation site. It shows how to initialize all the aspects of MVC in the correct way.
Models in SAPUI5 come in different classes to support different forms of data. For example, there is JSONModel, XMLModel, ODataModel, etc.
So to create a model, you need to first determine the specific type of model you need and use its specific constructor. For example, if you have JSON data (or simply a JavaScript object), you use the JSONModel:
var yourData = { "hello": "world" };
var oModel = new JSONModel(yourData);
Note that the above code assumes you are following the recommended way to use modules and that this code is wrapped with a sap.ui.define or sap.ui.require, where the module sap/ui/model/json/JSONModel is assigned to the variable JSONModel. The walkthrough shows this correct usage pattern. Accessing the constructor directly like the below is not recommended:
// Also probably works, but not the recommended way
var oModel = new sap.ui.model.json.JSONModel(yourData);
Your way of creating a controller is also not correct. You should preferably let the view instantiate the controller for you by providing it a controllerName, as shown in the walkthrough for Controllers.
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" controllerName="name.of.your.controller">
<!-- ... -->
</mvc:View>
If you need to manually instantiate a controller from code, use this:
Controller.create({ name: "name.of.your.controller" }).then(function(oController) {
// Do something with oController
});
This again assumes you have the module sap/ui/core/mvc/Controller linked to the variable Controller.
Before version 1.56, you can use the now-deprecated sap.ui.controller function to create controllers instead:
sap.ui.controller("name.of.your.controller", null, /*async=*/true).then(function(oController) {
// Do something with oController
});
Be aware that both of these examples load the controller asynchonously, as synchronous XHR is being globally deprecated outside of Workers, and thus the framework recommends you to use async only. In fact, the new way of loading does not even provide an option for sync loading.
I am trying to build a simple answer rating app (similar to the canonical Todo app) in Parse.
In Backbone, I could create a Model to represent a single answer and a Collection to represent a list of answers.
If I create a class in Parse's data browser, it corresponds to a Collection in Backbone. How can I specify a model (Parse.Model) in Parse.Collection if I have no way of creating one?
In Parse 1.2.13 (< 1.6), you can use the name of the class created in Parse Data Browser as the name of the model (individual item) in your js code.
That is, if you create a class named "Widget" in Parse Data Browser, you can use this in your js code:
var Widget = Parse.Object.extend ("Widget");
var Widgets = Parse.Collection.extend ({
model: Widget
}); // example collection
and proceed as usual with Backbone code.
I've been migrating my app from RethinkDb to Firebase and have run into a wall trying to get my collections to save when calling collection.create(). The odd thing is, I have two instances of Backbone.Firebase.Collection in my app and one of them is able to create new objects properly. The other collection, which is seemingly identical, cannot write data and generates no error messages.
I have two Collections, each with their own type of Model:
1) Projects (Collection) -> Project (Model)
2) Projects (Collection) -> Shots (Collection) -> Shot (Model)
Here are the definitions for the above collections/models:
/* Projects Collection - An ordered list of Projects */
var ProjectModelFirebase = require('../models/projectModelFirebase.js');
module.exports = Backbone.Firebase.Collection.extend({
model: ProjectModelFirebase,
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
/* Project Model - data layer for a single Project */
module.exports = Backbone.Firebase.Model.extend({
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
/* Shots Collection - An ordered list of Shots */
var ShotModelFirebase = require('../models/shotModelFirebase.js');
module.exports = Backbone.Collection.extend({
model: ShotModelFirebase,
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
/* Shot Model - data layer for a single Shot */
module.exports = Backbone.Firebase.Model.extend({
firebase: new Firebase(app.fbUrl),
initialize: function() {
}
});
In my Projects route (routes file), I bind the collection to the view normally and call this.collection.create with some inputs from the template. I'm able to successfully create projects in this way and they show up in my Forge with no problem. I call the view from my route function:
// Display list of latest projects
projectsCollectionFirebase = new ProjectsCollectionFirebase();
var projectsView = new ProjectsView({collection: projectsCollectionFirebase});
In my Project route (routes file), I bind the project collection to the view and retrieve the project's information from Firebase normally:
// Display a single project
projectModelFirebase = new ProjectModelFirebase({id: project});
var projectView = new ProjectView({model: projectModelFirebase});
I then proceed (projectView file) to create a new collection of shots:
shotsCollectionFirebase = new ShotsCollectionFirebase();
shotsView = new ShotsView({ collection: shotsCollectionFirebase, project: this.model.get('id') });
The Shots view (ShotsView file) renders the template and input fields for the user to input a shot.
From here, I call this.collection.create when a user clicks the 'Save' button. Backbone recognizes the new model and updates the view accordingly, but Firebase doesn't act on it. There is an error message in the console that states 'Save called on a Firebase model, ignoring.' but I do not have any saves called out explicitly in my code.
I've tried turning on debugging and noticed that the 'projects' create command causes this message:
r:0: update {"path":"/projects/test","value":{"shots":null}}
Whereas the 'shots' collection does not ever trigger an 'update' event.
The files are nearly identical. The only thing difference I can spot is that the first example has only one collection loaded at a time whereas the second example loads a collection, grabs the data, then loads another collection as a result.
Any help would be appreciated.
You can find the full code for the project in my repo here: https://github.com/bdickason/shots/tree/firebase
There are two modes of operation in Backfire, one with models/collection that have the word 'Firebase' in them, eg: Backbone.Firebase.Model/Backbone.Firebase.Collection; and the other mode that uses regular backbone collections and models but have the 'firebase' property defined on them that overrides the backbone sync() method.
These two modes should not be mixed and matched. For example, if you're using a Backbone.Firebase.Collection, all the models in that collection will automatically be synchronized with the server any time a change is made to any model (same for Backbone.Firebase.Model). Calling save, or sync doesn't do anything because the changes are saved and synced in realtime as they happen.
Sometimes this isn't what you want in the app, for example, you want the user to explicitely click a save button before saving anything to Firebase. In these cases, it's best to use a regular Backbone collection or model, and simply provide the firebase property on them. You then need to call sync or save explicitely to put any changes on the local model/collection into Firebase.
All, I am a newbie of Backbone. and I am trying to understand the Model of Backone. Especially how to define a Model. so far, I didn't saw a clear or formal way about how to define a Model for backbone.
For example Let's see the set method in help doc .
set
model.set(attributes, [options])
Set a hash of attributes (one or many) on the model.
Say we have some code like below . I think set method actually is assign a javascript object to the Model.
window.Employee = Backbone.Model.extend({
validate:function(attrs){
for(var key in attrs){
if(attrs[key] == ''){
return key + "can not be null";
}
if(key == 'age' && isNaN(attrs.age)){
return "age is numeric";
}
}
}
});
....
var attr = {}; // I can't not sure what is {} mean.
$('#emp-form input,#emp-form select').each(function(){
var input = $(this);//using jquery select input and select. and enumerate all of them.
attr[input.attr('name')] = input.val();//I am not sure what does it means
});
if(employee.set(attr)){
Employees.create(employee);
}
....
in this example ,I didn't saw the classical way which we can see in java class or c# class to define the class fields or methods. but only see a validate function .Is there anybody who can tell me more about it to help me understand? thanks.
To define a model in Backbone you have to extend the Backbone.Model object. For example if you'll like to create a new User model you could write something like this:
var User = Backbone.Model.extend({})
You can also overwrite some model methods to fill your needs. For example you can change the urlRoot attribute to tell the model where should he fetch the data.
Backbone models contain your data in the attributes attribute. You change those attributes by using the model set method and you can read the value stored in the model using the get method. So if you had some inputs where a user can enter information, for example creating a new user with his name and email and you have a form with a text input for both of them. You could do domething like this:
var user = new User;
user.set('name', $('#name').val());
user.set('email', $('#email').val());
attributes = {
name: user.get('name'),
email: user.get('email')
};
user.save(attributes);
There are a lot of ways to re-factor this code to make it look better but it help to see how you could use those methods. You should check the Backbone documentation to explore how they work a little bit more. Hope this helps!
PD: In my example I set an attribute a time, but you could also send a hash of attributes to set more values in one call.
The model in JS is basically a wrapper for data, with CRUD and simple validation functions. To work properly you need to make server functions to work with (ajax), I think this tutorial says it all http://backbonetutorials.com/what-is-a-model/. Instead of database the model works with your application server side.
If you have custom actions (not just add/edit/remove) on your data, you can manually "set()" data, use "onchange" event and refresh your view when needed. You can even attach "onchange" events only on specific fields and make custom functions in your view to handle each special field (for validation or display).
You can define fields at initialize and defaults value, but not custom functions (ofc you can do model.customFuntion() but I don't recommend it.
In order to make it more "clasical way" you need to use the other Backbone functions http://backbonejs.org/#Collection-Underscore-Methods and Backbone.Collection.
Perhaps this seems a bit backwards, but I have a view bound with Rivets.js for which I'd like the view to populate the model on initialization.
The usecase is that I'm using server-side rendering to return a snippet (the view) including rivets' data-attributes. So NO JSON is returned from server to client.
Now, by pressing 'edit' a user may put the content in 'edit'-mode, and start editing at will. (Using contenteditable, but this is out of scope here I guess).
So how to make sure the model is populated with values from the view on init?
I know that this question is a little outdated but I recentry tried rivets and I came across the same problem.
The solution:
// In your rivets configuration you disable preload:
rivets.configure({
templateDelimiters: ['[[', ']]'],
preloadData: false
});
// you bind your data
var binding = rivets.bind($('#auction'), {auction: auction});
// you manually publish it once to populate your model with form's data
binding.publish();
And that's it. I still don't know how to disable prelaod per bind
From the example on Rivets website (assign to 'rivetBinding')
var view = rivets.bind($('#auction'), {auction: auction});
doing rivetBinding.publish(); will bootstrap the model with values from the view for all bindings that have 'publishes = true'.
This question is old but it still has no accepted answer, so here goes:
You need to disable the preload configuration so rivets doesn't override whatever is in the input with what you have in your model at the time you do the binding. This can be done via the preloadData=false configuration, either globally (rivets.configure(...)) or view-scoped (third param to rivets.bind(...)).
After the binding, you need to publish the view (pull the values to your model). You also need to set up the observers via sync() call, otherwise your binded methods won't be triggered.
Using the same example as the previous answers:
var view = rivets.bind($('#auction'), { auction: auction }, {
preloadData: false
});
view.publish();
view.sync();