Backbone.localstorage not saving anything, with no errors - javascript

I'm trying to implement backbone.localstorage (https://github.com/jeromegn/Backbone.localStorage) in my application, but for some reason it's including it but not actually saving anything to localStorage, but it's also not throwing any errors either.
Here is my model code (I am using RequireJS):
define([
'backbone',
'common',
'localstorage'
],
function(Backbone, Common) {
//Define the App Namespace before anything else
var APP = Common.app_namespace || {};
APP.Models.ExampleModel = Backbone.Model.extend({
localStorage: new Backbone.LocalStorage("ExampleModel"),
//Set up default values
defaults: {
"user_name" : "awesome name",
"field 2" : "awesome field"
}
});
}
);
And here is where I'm calling it (using Marionette's regions):
var exModel = new APP.Models.ExampleModel({
"user_name" : "name!",
"field2" : "field!"
});
main_app_layout.header.show(new APP.Views.ExampleView({model: exModel}));
In terms of require, the page is loading, but I just don't think it's doing anything. Can anyone help?

I think you need to call the exModel.save() method for it to save to localStorage.

Related

Creation of a global, persistent object into Extjs

Good day all.
I'm into a big project that uses EXTjs (i guess it's 4.0), the project is huge and have several years behind.
I'm not into Extjs so I'm trying to learn what to do and how to do it, and my new task is to create a persistent, global object, available into the whole application in which I need to store some information that are used in different parts of the project (let's say for example that the user can set a particular property of this object to "true" while doing some actions and this "true" it will be used into another viewcontroller to enable some functions, things like this).
so, I've created a new file called userJsonMainModel.js :
Ext.define('Tac3.userJsonMainModel', {
extend: 'Ext.data.Model',
constructor: function() {
var userJsonMainModel = this;
userJsonMainModel.callParent(arguments);
userJsonMainModel.data.tmp = {};
},
testProperty:{foo:"bar"},
testMethod: function (){
console.log("testFunction called");
}
});
and in Application.js :
requires: [
...
'Tac.userJsonMainModel'
],
stores: ['Countries', 'Kpis', 'Dimensions'],
autoCreateViewport: false,
init: function() {
var controller = this
Ext.tip.QuickTipManager.init();
Ext.setGlyphFontFamily('FontAwesome');
var userJsonMainModel = controller.createUserJsonMainModel();
console.log("into init: ", this.userJsonMainModel.testProperty);
...
createUserJsonMainModel: function() {
var controller = this;
controller.userJsonMainModel = Ext.create('Tac3.userJsonMainModel', {
controller: controller
});
console.log("check if the jsonmainmodel exist ",controller.userJsonMainModel.testProperty);
},
this is actually working, now the second step is to access the same object from another view (or its viewcontroller), this is what I've done into a a viewController:
Ext.define('Tac3.view.udesign.UdesignController', {
extend: 'Ext.app.ViewController',
alias: 'controller.udesign',
init: function(view) {
...
console.log("into init: ", this.userJsonMainModel.testProperty);
}
and this is actually throwing a:
Uncaught TypeError: Cannot read property 'testProperty' of undefined
I was pretty sure the objects defined into application.js would be globally accessible, but I guess I'm wrong, or doing something in a wrong way.
since I've found quite no examples on this topic (which is probably because it is not a standard way to do this), I'd like to ask what I'm doing wrong?
Just define a class and require it in your application:
Ext.define('MyApp.Globals', {
singleton: true,
foo: 100,
bar: 'baz'
});

How is localized data binding set up with JSON files and XML views?

I have an XMLView home page containing some tiles. These tiles are populated from a JSON file. The tiles have a 'title' attribute which requires i18n data binding.
Part of the XML view:
<TileContainer id="container" tiles="{/TileCollection}">
<StandardTile
icon="{icon}"
title="{title}"
press="onPress" />
</TileContainer>
JSON file:
{
"TileCollection" : [
{
"icon" : "sap-icon://document-text",
"title" : "{i18n>foo}"
},
... etc
The old way I accomplished data binding was directly in the view with title="{i18n>foo}". Of course now I have essentially two layers of data binding, one in the JSON for the i18n, and one in the view to get the JSON (which gets the i18n).
This is also my Component.js where I set up the i18n model.
sap.ui.core.UIComponent.extend("MYAPP.Component", {
metadata: {
rootView : "MYAPP.view.Home", //points to the default view
config: {
resourceBundle: "i18n/messageBundle.properties"
},
... etc
init: function(){
sap.ui.core.UIComponent.prototype.init.apply(this, arguments);
var mConfig = this.getMetadata().getConfig();
var oRouter = this.getRouter();
this.RouteHandler = new sap.m.routing.RouteMatchedHandler(oRouter);
oRouter.register("router");
oRouter.initialize();
var sRootPath = jQuery.sap.getModulePath("MYAPP");
var i18nModel = new sap.ui.model.resource.ResourceModel({
bundleUrl : [sRootPath, mConfig.resourceBundle].join("/")
});
this.setModel(i18nModel, "i18n");
}
This question arose from discussion about another question, so there may be more info there for anyone interested. Link
The approach I usually take is using a formatter function, which sole purpose is to get the correct localized value for a certain key (which is maintained in the resource model, and driven by the data model)
For instance, the Tile UI would look like this:
<TileContainer id="container" tiles="{/tiles}">
<StandardTile
icon="{icon}"
type="{type}"
title="{ path : 'title', formatter : '.getI18nValue' }"
info="{ path : 'info', formatter : '.getI18nValue' }"
infoState="{infoState}"
press="handlePress"/>
</TileContainer>
(Notice the formatter function getI18nValue for properties title and info; these are the properties to be translated. The other properties come as-is from the bound JSONModel)
The model could look like this:
tiles : [
{
icon : "sap-icon://inbox",
number : "12",
title : "inbox", // i18n property 'inbox'
info : "overdue", // i18n property 'overdue'
infoState : "Error"
},
{
icon : "sap-icon://calendar",
number : "3",
title : "calendar", // i18n property 'calendar'
info : "planned", // i18n property 'planned'
infoState : "Success"
}
]
where the title and info property values of the JSONModel (for instance, 'inbox' and 'overdue') correspond with a key in your resourcebundle files (and thus your ResourceModel)
The formatter function in the controller (or better, in a standalone JS file, for re-use in multiple views) is then pretty simple:
getI18nValue : function(sKey) {
return this.getView().getModel("i18n").getProperty(sKey);
}
It does nothing more than supplying the value from the model (for instance, 'inbox') and returning the localized value for this key from the resource model

Ext.getStore() returns undefined while testing with Siesta

In ExtJs application to make getStore work controllers, models and stores are added in Application.js. But for testing with siesta, I can't make any changes in Application.js.
Calling Ext.getStore(storeId) directly is returning undefined. I have tried by adding model in preload, but it doesn't help.
What should I do for this?
-------------------------Code in the testFile AnalysisController.t.js ---------------------
StartTest(function(t){
var testStore = Ext.getStore('Nm.store.analysis.TestStore'); //testStore is undefined
});
-------------------------Code in testModel.js-------------------------
Ext.define('Nm.model.analysis.TestModel',
{
extend: 'Ext.data.Model',
fields: [
{name:'lastName',type:'string'},
{name:'age',type:'int'},
{name:'relationDescription',type:'string'},
{name:'dateOfBirth',type:'date',dateFormat: 'm-D-Y'}
]
});
-------------------------Code in testStore.js-------------------------
Ext.define('Nm.store.analysis.TestStore',{
extend : 'Ext.data.Store',
requires: ['Nm.model.analysis.TestModel'],
model : 'Nm.model.analysis.TestModel'
});
-------------------------Code in harness file testIndex.js----------------
var Harness = Siesta.Harness.Browser.ExtJS;
Harness.configure({
title : 'Samples',
loaderPath : { 'Nm' : 'app' },
preload : [
"http://cdn.sencha.io/ext/gpl/4.2.0/resources/css/ext-all.css",
"http://cdn.sencha.io/ext/gpl/4.2.0/ext-all-debug.js"
]
});
Harness.start({
group : 'Controller',
items : [
'test/AnalysisController.t.js'
]}
);
to use Ext.getStore() you have to register the store I think.
plz read
Check if Ext is defined in your test file. Although Siesta supports Ext, the variable Ext is not defined by default. The simplest way to do this is just by adding the following at the top of your test:
var Ext = test.global.Ext;
To load a "global" store via Ext.getStore(), it must be registered in the application.
To do that, ensure it is added to the stores array in your main app class
Ext.application({
extend: 'Ext.app.Application',
stores: [ add global store classes here ]
});

Backbone and best practice getting config JSON

I've got a JSON file that looks like this.
{
"config": {
"setting1": 'blabla',
"setting2": 'blablabla'
},
"content": {
"title": "Title of an exercise.",
"author": "John Doe",
"describtion": "Exercise content."
},
"answers": [
{
"id": "1",
"content": "Dog",
"correct": true
},
{
"id": "2",
"content": "Fish",
"correct": false
}
]
}
Than, I create a Backbone View, combined from content model, and answers (which are randomly selected, but It's not most important now).
I've also got a config, which has settings that will determinate which view and collection methods to use.
It seems like a simple task, but as I'm new to Backbone, I'm wondering which is the best way to fetch JSON file, creating one model with url to JSON and than using parse and initialize creating another models and collections (with answers), or using $.getJSON method that will create exactly the models that I need?
I was trying using $.getJSON
$.getJSON(source, function(data) {
var contentModel = new ContentModel(data.content);
var contentView = new ExerciseView({ model: contentModel });
var answerCollection = new AnswersCollection();
_.each(data.answers, function(answer) {
answerCollection.add(answer);
});
var answersView = new AnswersView({collection: answerCollection});
$(destination).html( contentView.render().el );
$('.answers').append( answersView.el );
)};
But It doesn't seem very elegant solution, I know that this application needs good architecture, cause It will be developed with many other Views based on 'config'.
Hope you guys give me some suggestions, have a good day!
I think what you've done works fine and is correct. But you may need to refactor a little bit since "it will be developed with many other Views based on 'config'".
IMHO, the first thing you need to do is to handle failure in your getJson callback to make the process more robust.
Second, it is useful to create a Factory to generate your views because your logic is to generate different views based on the config data from server. So the factory maybe:
contentViewFactory.generate = function(data) {
var config = data.config;
....
var ActualContentView = SomeContentView;
var contentModel = new ContentModel(data.content);
return = new ActualContentView({ model: contentModel });
}
If your logic is simple, you can have a dict map from config to view class like:
var viewMaps = {
"exercise" : ExerciseView,
"other": SomeOtherView,
//....
}
And if every workflow has a AnswersView you can keep that in your getJSON callback. So maybe now your getJSON looks like this:
$.getJSON(source, function(data) {
// keep the config->view logic in the factory
var contentView = contentViewFactory.generate(data);
var answerCollection = new AnswersCollection();
_.each(data.answers, function(answer) {
answerCollection.add(answer);
});
var answersView = new AnswersView({collection: answerCollection});
$(destination).html( contentView.render().el );
$('.answers').append( answersView.el );
})
.fail(){
//some failure handling
};
Furthermore, if you have common logics in you "ContentView"s, it's natural that you can have a "BaseContentView" or "ContentViewMixin" to extract the common logic and use extends to make your code more OO:
Backbone.View.extend(_.extend({}, ContentViewMixin, {
//.....
}
So if someone is trying to add a new ContentView, he/she just needs to add some code in the factory to make the new View be generated by config. Then extends the ContentViewMixin to implement the new View.

Ember js - Hasmany relationships breaks after updating other tables

I am using Ember.js with local-storage-adapter. I have a weird problem while updating records.
I have a post and comments model with hasMany relationships:
App.Post = DS.Model.extend({
title: DS.attr('string'),
comments: DS.hasMany('comment', {
async: true
})
});
App.Comment = DS.Model.extend({
message: DS.attr('string')
});
These are my post and comments controllers:
App.PostsController = Ember.ArrayController.extend({
newTitle: '',
actions: {
create: function() {
var title = this.get('newTitle');
var post = this.store.createRecord('post', {
title: title
});
this.set('newTitle', '');
post.save();
}
}
});
App.CommentsController = Ember.ArrayController.extend({
needs: "post",
post: Ember.computed.alias("controllers.post.model"),
newMessage: '',
actions: {
create: function() {
var message = this.get('newMessage');
var comment = this.store.createRecord('comment', {
message: message
});
var post = this.get('post');
var comments = post.get('comments');
if (comments.get('content') == null) comments.set('content', []);
comments.pushObject(comment);
comment.save();
post.save();
}
}
});
While creating records hasMany relations updated correctly.
{
"App.Post": {
"records": {
"0v66j": {
"id": "0v66j",
"title": "post1",
"comments": ["p31al", "tgjtj"]
}
}
},
"App.Comment": {
"records": {
"p31al": {
"id": "p31al",
"message": "comment 1"
},
"tgjtj": {
"id": "tgjtj",
"message": "comment 2"
}
}
}
}
The problem occured while editing post. The relationships are gone after editing the post record. I did some searching and found this code:
DS.JSONSerializer.reopen({
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
// alert(relationshipType);
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany' || relationshipType === 'manyToOne') {
json[key] = Ember.get(record, key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany
// relationships
}
}
});
This did the trick and it worked fine. But now I have another problem. If I edit any other record, all the id references are replaced by whole object like this:
{"App.Post":{"records":{"0v66j":{"id":"0v66j","title":"post2","comments":[**{"message":"comment 1"},
{"message":"comment 2"}**]},"8nihs":{"id":"8nihs","title":"post3","comments":["b4v2b","dbki4"]}}},
"App.Comment":{"records":{"p31al":{"id":"p31al","message":"comment 1"},"tgjtj":{"id":"tgjtj","message":"comment 2"},
"b4v2b":{"id":"b4v2b","message":"comments3"},"dbki4":{"id":"dbki4",
"message":"comments4"}}}}
Comment refrences should be comments":["p31al","tgjtj"] like this. but the ids are replaced as "comments":[{"message":"comment 1"},{"message":"comment 2"}]
When using ApplicationSerializer which extends LSSerializer, it seems to work.
Maybe it got fixed since asked?
I've noticed a few things in my path with Ember... and especially Ember-Data.
One of them is when dealing with associations I've had to manually re-add in the associations saving and having to re-save, and use addObject to in-memory associations as you're using a bit here. :)
Note that this usually only happens when I'm updating more than one new object at once. For example, if your post is new, and your comment is also new.
I'm a little worried to see the following code in your codebase, because it shouldn't need to be there. You shouldn't ever have null or non-array objects in your associations. I'm not sure what hackery you did with the Adapter and why it was necessary, but I hope that wasn't the reason:
if(comments.get('content') == null)
comments.set('content', []);
Anyway, the following code is how I would probably write your create action. It might help. I hope it does.
create: function() {
// get the post for association on the new comment
var post = this.get('post');
// get the message to store on the new comment
var message = this.get('newMessage');
var comment = this.store.createRecord('comment', {
message : message,
post : post
});
comment.save().then(function(savedComment) {
post.get('comments').addObject(savedComment);
});
}
Note that it's a lot simpler. Generally if you're doing tricky complicated things, something's amiss and it's time to go back to basics and add one thing at a time, testing thoroughly between additions. :)
Good luck!

Categories

Resources