I am implementing a Blog Engine as a learning exercise for a new job. I have a Backbone.js Collection class called BlogList that is composed of BlogModel objects (a BlogModel is a single post to a blog). I have a masterBlogList that keeps all blog posts in memory for the lifetime of the application (I realize this is not a realistic design, but it is part of the spec).
I have chosen to use masterBlogList to hold the canonical state of the application. All new posts, edits, etc. are persisted to the database (MongoDB) as well as masterBlogList. When I want to display a subset of the posts in masterBlogList, I copy them into a new BlogList instance and then narrow this new instance down based on search criteria. Again, I realize this might not be the best design (cloning BlogModels and BlogLists), but it is what I've got and I'd prefer not to rework it.
The problem is that copying one BlogList to another is not working. Even when the source list is non-empty, the destination list always ends up being empty. I have tried to debug this every which way with no luck. Here is the relevant portion of the BlogList source code:
// BlogList
$ (function () {
App.BlogList = Backbone.Collection.extend ({
model : App.BlogModel,
url : '/blog-entries',
comparator : function (a) {
return -(new Date (a.get ('date')));
},
populateFromMemory : function (sourceList) {
// this.reset ();
var self = this;
sourceList.each (function (postModel) {
self.add(postModel);
});
var foo = new App.BlogModel();
this.add(foo);
},
(continued...)
Even the last bit regarding foo is not working. I've also tried adding a clone() of postModel and also new App.BlogModel(postModel.toJSON()).
Any help would be extremely appreciated!
Sorry to have bothered anyone :<, but I got it working. The code actually does work as written above. The problem is that my search criteria were filtering out all of the posts, so I wasn't seeing anything. End of a long day! Thanks to those who tried to help me...
Related
I need to run some client-side javascript from a button in a form view in Odoo 8. This button runs a python method which returns this dictionary:
{"type": "ir.actions.client",
"tag": "my_module.do_something",}
do_something is defined in a .js file as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.Action");
instance.my_module.Action = instance.web.Widget.extend({
init: function() {
// Do a lot of nice things here
}
});
};
Now, the javascript is loaded and executed properly, but even before launching the init function, Odoo loads a brand new, blank view, and once the javascript is over I can't get browse any other menu entry. In fact, wherever I click I get this error:
Uncaught TypeError: Cannot read property 'callbackList' of undefined
What I need instead is to run the javascript from the form view where the button belongs, without loading a new view, so both getting the javascript stuff done and leaving all callbacks and the whole environment in a good state. My gut feeling is that I shouldn't override the init funcion (or maybe the whole thing is broken, I'm quite new to Odoo client-side js) , but I couldn't find docs neither a good example to call js the way I want. Any idea to get that?
Sorry, I don't work on v8 since a lot of time and I don't remember how to add that, but this might help you: https://github.com/odoo/odoo/blob/8.0/doc/howtos/web.rst
Plus, if you search into v8 code base you can find some occurence of client actions in web module docs https://github.com/odoo/odoo/search?utf8=%E2%9C%93&q=instance.web.client_actions.add
Thanks to the pointers simahawk posted in another answer, I have been able to fix my js, which is now doing exactly what I needed. For your reference, the code is as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.action");
instance.my_module.action = function (parent, action) {
// Do a lot of nice things here
}
};
TL; DR;
I'm looking for trite example of DDD node.js application.
Hi,
I'm going to create node application. I wonder that I can not find any example of application with business logic separated in domain.
OK, there are some examples like:
https://github.com/adrai/node-cqrs-domain - but this is whole CQRS with event sourcing implementation.
My idea is to do that like that:
//domain/book.js
function Book(title, author)
{
this._title = title;
this._author = author;
}
// domain methods ...
//infrastructure/persistance/repository/book-repository.js
function BookRepository()
{}
BookRepository.prototype.save(book)
{
var bookModel = mappers.mapToOrm(book);
return bookModel.save();
}
// [...] get, getAll, getNextId
//infrastructure/persistance/orm/book.js
//using http://bookshelfjs.org/
var Book = bookshelf.Model.extend({
tableName: 'books'
});
//infrastructure/mappers/book-mapper.js
function mapToOrm(book) {
//mapping [...]
return new persistance.Book();
}
function mapToDomain(domain) {
//mapping [...]
return new domain.Book();
}
but on the other hand I've never seen any similar solution (with domain model, orm model, repository and mappers). Am I thinking in the right way? Maybe there is no reason to separate business logic in domain in node.js applications. If so, why? If not, can you send me an example of DDD implementation or improve my code?
[2017/01/13]
I've created sample application in TypeScript. For now without repositories and not much services. Issues and pull requests are welcome.
https://github.com/dawiddominiak/ddd-typescript-bin-packing-problem-solution
I'm very new to Node.js world.
But I believe if you do your work using TypeScript with Node you can force most of DDD principles to be used.
The problem "and advantage in the same time" in node.js that there aren't so restrictions like we have in OOP languages like C# or Java. and this freedom "and messy" of JavaScript making create robust complex DomainModel and Business logic very hard
I'm looking to do the same thing at the moment, and I'm coming from the Ruby world. So, let me do 2 things:
Point you to the best Ruby implementation I've seen of Domain-Driven Design I have found, Hanami: http://hanamirb.org/guides/models/overview/ which you could use as a reference.
Discuss what I'm finding (literally right now, as I type) to attempt to find the analogs in Node.
I've found this page: https://github.com/sindresorhus/awesome-nodejs
which catalogs a ton of high-quality / high-popularity Node packages.
The first thing is, we need something that is going to do validation and schema construction for our Domain Models. Just looking at the first entry in the data validation section, Joi seems to be a decent choice for that:
https://github.com/hapijs/joi
For Persistence of the domain objects, I'm just setting up a stub object, borrowing from Hanami's interface:
var repo = {
find: function(entity_name, id) {
// - Fetch an entity from the collection by its ID
},
create: function(entity_name, data) {
// – Create a record for the given data and return an entity
},
update: function(entity_name, id, data) {
// – Update the record corresponding to the id and return the updated entity
},
delete: function(entity_name, id) {
// – Delete the record corresponding to the given entity
},
all: function(entity_name) {
// - Fetch all the entities from the collection
},
query: function(entity_name, query_object) {
},
first: function(entity_name) {
// - Fetch the first entity from the collection
},
last: function(entity_name) {
// - Fetch the last entity from the collection
},
clear: function(entity_name) {
// - Delete all the records from the collection
}
}
module.exports = repo
whether you choose to use Bookshelf, Sequelize, or even the LoopBack framework, you can code an object that is going to fit the above interface that then does the dirty work of integrating with those frameworks.
If I were to try different ORM's, I would create a different repo object for each of the above. Notice that as I've written it, the repo is a singleton that is aware of different entities and how to persist them. In many cases, this will no doubt delegate to different repository objects on a per-entity basis. However, that might not always be true. a simple in-memory repo, could just have an array of objects for each entity.
That leaves Services/Interactors - The functions/classes that actually do work. These are easy - they are the ones that take a domain object, perform some business logic, and in the CRUD cases, make a call out to the Repository. A probably-syntactically-wrong example:
const repository = require('./myFileRepository')
function createBook(bookEntity) {
if(bookEntity.valid?) {
repository.create('book', bookEntity)
return true
}
else {
return { error: 'book not valid' }
}
}
module.exports = createBook
for the Service functions, I just today learned about Node Machines, and they seem like a really smart idea: http://node-machine.org
they seem to be a JS-attempt at monads + documentation. so I'm considering writing them up like that.
anyway, given it's been a year since your post, you've probably moved on. hope this helps you / the community!
Many would argue that JavaScript is NOT well suited to modeling a complex problem into a domain model and then into code. That's especially the case if the domain is in business, industry and commerce, rather than in computer or data science.
I'm not saying one can't create a domain model in JavaScript. Just like one could create one in C. But does that mean one should?
The example you give uses some terminology in domain-driven design, but misses the whole purpose and ethos of applying it.
I'm working on a small blog engine where the user can create blog entry and possible to link tags to an entry. It is many-to-many relation, but due to that Breeze cannot yet manage this relation I have to expose the join table to breeze so that I can persist the data step-by-step. And my problem is here.
Tables:
BlogEntry
BlogEntryTag
Tag
Scenario:
user opens the "new blog entry" form or selects an existing one to be edited
enters the text, etc
selects one or more tags
Business logic:
create a new entity by Breeze / query the selected one
save the blog entry (1st server call which gives back the blog_id if the blog entry is new one)
check the already existing connections between the tags and blog entry, if the blog entry is edited then the already existing blogEntry-tag relations might change ( 2nd server call)
based on the tag name selecting the tag_id from tag table (3rd server call)
create the BlogEntrytag entities by breeze
persist the BlogEntrytag entities into database ( 4th server call)
I think the order must be consecutive.
I have this code and as you can see the attached screenshot the console logging marked by '_blogEntryEnttity' does not wait until the data returns from the server and it will be executed before the console logging marked by '_blogEntryEnttity inside'. The code will throw a reference exception when it tries to set up the title property a few line later.
var blogEntryEntityQueryPromise = datacontext.blogentry.getById(_blogsObject.id);
blogEntryEntityQueryPromise.then(function (result)
{
console.log('result', result);
_blogEntryEntity = result[0];
console.log('_blogEntryEnttity inside', _blogEntryEntity);
//if I need synchronous execution then I have to put the code here which must be executed consecutively
});
console.log('_blogEntryEnttity', _blogEntryEntity);
}
//mapping the values we got
_blogEntryEntity.title = _blogsObject.title;
_blogEntryEntity.leadWithMarkup = _blogsObject.leadWithMarkup;
_blogEntryEntity.leadWithoutMarkup = _blogsObject.leadWithoutMarkup;
_blogEntryEntity.bodyWithMarkup = _blogsObject.bodyWithMarkup;
_blogEntryEntity.bodyWithoutMarkup = _blogsObject.bodyWithoutMarkup;
console.log('_blogEntryEnttity', _blogEntryEntity);
The example comes from here.
My question is that, why it is not wait until the data comes back? What is the way of handling cases like this?
However, I figured out that, if I need synchronous execution then I should place the code into the success method following the data retrieving from the promise. However, I really don't like this solution because my code will be ugly after a while and hard to maintain.
The datacontext.blogentry.getById looks like below and the implementation is in an abstract class, you can find the code below too. The whole repository pattern comes from John Papa's course on Pluralsight.
Repository class method
function getById(id)
{
return this._getById(this.entityName, id);
}
Abstract repository class method. According to Breeze's documentation page the EntityQuery class' execute method returns a Promise.
function _getById(resource, id) {
var self = this;
var manager = self.newManager;
var Predicate = breeze.Predicate;
var p1 = new Predicate('id', '==', id);
return EntityQuery.from(resource)
.where(p1)
.using(manager).execute()
.then(success).catch(_queryFailed);
function success(data) {
return data.results;
}
}
I appreciate your help in advance!
I don't think you need all these round trips. I'd do this:
Query all available Tag entities, so they'll be in the EntityManager's cache (you need these to populate the UI anyway).
If it's an existing BlogEntry, just query the BlogEntry and all its associated BlogEntryTag entities; Breeze will connect the BlogEntryTags to their associated Tags in the cache. You'll add/delete BlogEntryTags if the user selects/unselects Tags for the BlogEntry.
var query = EntityQuery.from("BlogEntries").where("id", "==", id).expand("BlogEntryTags");
If it's a new BlogEntry, it won't have any BlogEntryTags. You'll create these when you save, after the user selects some tags.
Save the added/updated BlogEntry and any added/deleted BlogEntryTag entities to the database in a single saveChanges call.
See the Presenting Many-to-Many doc and its associated plunker for a deeper dive. The UI is different from what you want, but the underlying concepts are useful.
why it is not wait until the data comes back?
Because promises don't magically synchronize execution. They're still asynchronous, they still rely on callbacks.
What is the way of handling cases like this?
You need to put the code that should wait in the then callback.
However, I really don't like this solution because my code will be ugly after a while and hard to maintain.
Not really, you can write concise and elegant asynchronous code with promises. If your code is becoming too much spaghetti, abstract parts of it in own functions. You should be able to get to a clean and flat promise chain.
So basically, I'm trying to introduce modifications in OpenERP's POS inteface from version 6.1. I see that the layout of this view can be found at /static/src/xml/pos.xml. What I want is to modify this view from my own addon (thus, not altering the original pos addon) and as far as I know, there is no way of inheriting this view to add changes (or is there?). So after studying the module, I'm trying to override its js function to slip in my own pos.xml with all my modifications (a copy of the original pos.xml, but with name 'PointOfSale_Mine' and other modifications). So far, I have added my own .js as follows:
openerp.my_pos = function(db) {
db.point_of_sale.PointOfSale = db.point_of_sale.PointOfSale.extend({
render: function() {
this._super.apply(this,arguments);
return qweb_template("PointOfSale_Mine")();
//return this._super.qweb_template("PointOfSale_Mine")();
//return db.point_of_sale.qweb_template("PointOfSale_Mine")();
}
})
};
And of course, I'm getting the error "qweb_template is not defined" as my JS skills and my knowledge regarding OpenERP6.1's new web framework is quite limited. I would really like to know how can I call the same method that the original 'render' function calls (You can see my useless attempts commented in the code above). Or is my whole approach wrong and there is a better way of introducing my changes to the template?
Thanks in advance. Any help will be appreciated.
Ok. After some trial and errors I came up with this code to do the trick:
openerp.my_pos = function(db) {
db.point_of_sale.PointOfSale = db.point_of_sale.PointOfSale.extend({
render: function() {
var rend = this._super();
var jdoc = $(rend);
jdoc.find('.pos-payment-container').prepend('<input type="text" value=""/>')
return jdoc[0].outerHTML;
}
})
};
It does not replace the entire pos.xml template as I was initially attempting, but it is probably better as you inherit the current template and introduce your modifications only (even if you have to .prepend() a big chunk of html code)
I'm a newbie javascript developer (first post here!) and been recently trying to play with backbone.sync. I've been reading through the todo example and notice that it uses backbone-localstorage. My feeling is that backbone-localstorage was just a quick implementation that the author used for demo purposes. I also noticed that the keys are randomly generated, whereas I would like something that would allow me to name my own key values.
I've been looking at jstorage (www.jstorage.info), and would really appreciate some pointers (preferably with code samples) on how to integrate it with backbone.js. I imagine backbone.sync would need to be overriden somehow as is done in backbone-localstorage.
Alternatively, what localStorage plugin/wrapper would you recommend, and how would it integrate with backbone?
Thanks for help in advance.
My feeling is that backbone-localstorage was just a quick implementation that the author used for demo purposes.
Exactly right. I'd say that the implementation is fine for most things, but what support you can get for it is probably minimal.
I also noticed that the keys are randomly generated, whereas I would like something that would allow me to name my own key values.
This isn't really correct. I assume you are referring to this:
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// have an id of it's own.
create: function(model) {
if (!model.id) model.id = model.attributes.id = guid();
this.data[model.id] = model;
this.save();
return model;
}
Here, what's happening is that when a create is called on a model, it tries to determine if an id has been set on the model, and if no such id is provided, then the guid function is used to build one. This isn't setting a key randomly, it's fulfilling the requirement that every saved model should have an id (by assigining a random one).
Modifying the backbone-localstorage.js code should be fairly trivial. Let's look at the store constructor as an example
Before:
var Store = function(name) {
this.name = name;
var store = localStorage.getItem(this.name);
this.data = (store && JSON.parse(store)) || {};
};
The only thing we need to update here is the call to localStorage:
After:
var Store = function(name) {
this.name = name;
//Notice here, that jStorage gives us the option to define a default.
var store = $.jStorage.get(this.name, {});
this.data = store;
};
Similarly simple is the save function:
Before:
save: function() {
localStorage.setItem(this.name, JSON.stringify(this.data));
}
again, simply update the call to localStorage:
After:
save: function() {
$.jStorage.set(this.name, this.data);
}
Update: jStorage handles all the JSON.stringify, and JSON.parse for you, so I've updated the above code to reflect that.
Easy peasy, right!
Anyways, this is a great exercise, and I wish you the best of luck. I hope that I've been able to help you out.
P.s. One thing that bothers me about the localStorage plugin is that it uses model.attributes.xxx, where it's better to use model.get("xxx"). This way, if they ever change the internals of model change, your code won't break.
P.p.s. as far as how to generate guids, and weather a random guid is appropriate for you, depends upon your domain. With the TODO example, there is no backing database to sync with, so any old guid would do the trick, but in many other cases, you may be using html5 storage to create an offline version of your app, so id's need to be compatable with the db. In these cases, using a random guid is probably not that great an idea, but the one provided by the backbone-localstorage plugin is designed so that it isn't likely to collide with your db's actual id's, so it's not _that bad. There isn't really a right answer here, so do what makes sense for your domain.
You should probably look first at the local storage plugin that backbone.js provides. There are plenty of code samples that should give you an idea of how you would swap in jstorage as the underlying storage mechanism. See it here:
backbone-localstorage.js