Updating presentation layer when the mongo document changes - mongodb

I have a list of dogs in a table that have an underlying dog model and dog collection. When I update the dogName of a dog document in the mongo collection I want the table list item to update and show the new dog name without having to refresh the page.
I thought this was supposed to happen when you this.listenTo(this.model, 'change', this.render);
How can I get the table row item to update when the model changes??
window.Dog = Backbone.Model.extend({
urlRoot: "/dogs",
idAttribute:"_id",
initialize: function() {
}
defaults:{
_id: null,
dogName: "",
}
});
window.DogCollection = Backbone.Collection.extend({
model: Dog,
url: "/dogs/user/",
});
window.DogListView = Backbone.View.extend({
initialize: function () {
this.listenTo(this.model, 'change', this.render);
this.render();
},
render: function () {
var dogs = this.model.models;
$(this.el).html(this.template());
for (var i = 0; i < dogs.length; i++) {
this.$('#dogsTable tbody').append(
new DogListItemView({model: dogs[i], no: i+1}).render().el
);
}
this.$('#dogsTable').dataTable({
"bAutoWidth": false,"iDisplayLength": 50
});
return this;
}
});
window.DogListItemView = Backbone.View.extend({
tagName: "tr",
initialize: function (options) {
this.listenTo(this.model, 'change', this.render);
this.model.bind("change", this.render, this);
this.model.bind("destroy", this.close, this);
this.no = options.no;
this.render();
},
render: function () {
$(this.el).html(this.template({
no: this.no,
id: this.model.get("_id"),
dogName: this.model.get("dogName"),
}));
return this;
},
events: {
"click .delete": "deleteDog",
}
});
And finally in backbone controller I use this to load the view:
var dogList = new DogCollection();
dogList.url = "/dogs/user/" + this.user.get("_id");
dogList.fetch({
success: function() {
$('#content').html(new DogListView({model: dogList}).el);
}
});

What you're doing right now is:
Create some views (item- and collectionViews)
Define a collection
Set an url for this collection
Fetch the collection and on succes
Display the fetched data in these views
This is totally fine and these views will (probably, did not test your code) update once a change occurs in any of your models in the collection.
However, your application has no way of knowing that something is changed in your mongo database once it has fetched the data. If you would like to obtain this functionality, you could do for example one of the following;
Make the collection poll (and thus refetch) once in a while.
Inform your application that something has changed on the server using websockets. If you'd like to do this, you can use a library like http://socket.io

Related

Is it possible to bind two models to one control?

I need to display two numbers in my StandardTile. The data source is a SOAP web service, which I had to call twice with different parameters to obtain these two numbers. Is there any way to fill the tile with these two figures? I tried creating one XMLModel per each ajax call to the web service, and then binding the property of the control to the node from the response, but I'm just getting the same figure duplicated.
Below is my onInit method in the controller
onInit: function () {
// callback from ajax request
SOAPRequester.getMessageOverview(function (data) {
var oModel = new sap.ui.model.xml.XMLModel();
oModel.setData(data);
var oStandardTile = sap.ui.getCore().byId("__xmlview0--messageOverviewTile");
if (oStandardTile !== undefined) {
oStandardTile.setModel(oModel, "overview");
oStandardTile.bindProperty("number", {
path: "/SOAP-ENV:Body/rpl:getMessageListResponse/Response/rn5:number",
model: "overview"
});
}
});
//callback from the second ajax call
SOAPRequester.getErrorMessages(function (callbackData) {
var oModel = new sap.ui.model.xml.XMLModel();
oModel.setData(callbackData);
var oStandardTile = sap.ui.getCore().byId("__xmlview0--messageOverviewTile");
if (oStandardTile !== undefined) {
oStandardTile.setModel(oModel, "overview");
oStandardTile.bindProperty("infoState", "Error");
oStandardTile.bindProperty("info", {
path: "/SOAP-ENV:Body/rpl:getMessageListResponse/Response/rn5:number",
model: "overview"
});
}
});
},
Yes, it is. You are using the same model name twice, thus the firs one is not visible anymore. Simply use different model name, i.e. "overview" and "overview2" or what ever you prefer:
onInit: function () {
// callback from ajax request
SOAPRequester.getMessageOverview(function (data) {
var oModel = new sap.ui.model.xml.XMLModel();
oModel.setData(data);
var oStandardTile = sap.ui.getCore().byId("__xmlview0--messageOverviewTile");
if (oStandardTile !== undefined) {
oStandardTile.setModel(oModel, "overview");
oStandardTile.bindProperty("number", {
path: "/SOAP-ENV:Body/rpl:getMessageListResponse/Response/rn5:number",
model: "overview"
});
}
});
//callback from the second ajax call
SOAPRequester.getErrorMessages(function (callbackData) {
var oModel = new sap.ui.model.xml.XMLModel();
oModel.setData(callbackData);
var oStandardTile = sap.ui.getCore().byId("__xmlview0--messageOverviewTile");
if (oStandardTile !== undefined) {
oStandardTile.setModel(oModel, "overview2");
oStandardTile.bindProperty("infoState", "Error");
oStandardTile.bindProperty("info", {
path: "/SOAP-ENV:Body/rpl:getMessageListResponse/Response/rn5:number",
model: "overview2"
});
}
});
},
Hint: You could also improve your code a little, i.e.
call this.getView().byId("messageOverviewTile") or if you have the right UI5 version this.byId("messageOverviewTile") instead of sap.ui.getCore().byId("__xmlview0--messageOverviewTile")
Do the binding for your controls in your view and then in onInit() call this.getView().setModel(oModel, "overview") and this.getView().setModel(oModel, "overview2")

How to preserve `LokiJS` data in `localstorage`

my data base is not preserved in local storage. any one help me here? I guess that, lokijs will preserve the data in localstorage by default. But after refresh I am not getting the updated datas.
here is my code :
jQuery(document).ready(function($) {
var db = new loki("test", {
autosave: true, //setting to save
autosaveInterval: 1000
});
var children = db.addCollection('children')
//adding defualt datas
children.insert({name:'Sleipnir', legs: 8})
children.insert({name:'Jormungandr', legs: 0})
children.insert({name:'Hel', legs: 2});
$("#local").on("click", function(e){
e.preventDefault();
var callback = function( data ){
console.log("call back data", data );
}
$.mockjaxSettings.namespace = "";
myCaller( callback );
})
$("#remote").on("click", function(e){
e.preventDefault();
$.mockjaxSettings.namespace = "///";
myCaller();
});
$("#getData").on("click", function(e){
e.preventDefault();
var child = children.find();
console.log( "children", child );
});
$("#insertData").on("click", function(e){
e.preventDefault();
//inserting new data, but after refresh i am not getting it!!!
children.insert({name:'Mohamed Arif', legs: 2});
})
});
Your data are preserved in local storage, you just erase them every time you load a page with var children = db.addCollection('children')
Replace it by :
var children
db.loadDatabase({}, () => {
children = db.getCollection('children')
if(!children) {
children = db.addCollection('children')
}
})
So with this, if your collection doesn't exist you create it and you don't erase it if it already exists.
I quickly made a plunker that does what you asked : https://plnkr.co/edit/eOgc1ZoQioaI4JYpeggY

Debugging Ember-cli-mirage when routes are not being called

I have successfully created one route in ember-cli-mirage, but am having trouble loading the related data.
The API should be returning JSON API compliant data.
I'm not really sure if there are any good methods or not for debugging mirage's request interception. Here is my config.js
export default function() {
this.urlPrefix = 'https://myserver/';
this.namespace = 'api/v1';
this.get('/machines', function(db, request) {
return {
data: db.machines.map(attrs => (
{
type: 'machines',
id: attrs.id,
attributes: attrs
}
))
};
});
this.get('/machines/:id', function(db, request){
let id = request.params.id;
debugger;
return {
data: {
type: 'machines',
id: id,
attributes: db.machines.find(id),
relationships:{
"service-orders": db["service-orders"].where({machineId: id})
}
}
};
});
this.get('/machines/:machine_id/service-orders', function(db, request){
debugger; // this never gets caught
});
}
Most of this is working fine (I think). I can create machines and service orders in the factory and see the db object being updated. However, where my application would normally make a call to the api for service-orders: //myserver/machines/:machine_id/service-orders, the request is not caught and nothing goes out to the API
EDIT:
This is the route that my Ember app is using for /machines/:machine_id/service-orders:
export default Ember.Route.extend(MachineFunctionalRouteMixin, {
model: function() {
var machine = this.modelFor('machines.show');
var serviceOrders = machine.get('serviceOrders');
return serviceOrders;
},
setupController: function(controller, model) {
this._super(controller, model);
}
});
And the model for machines/show:
export default Ember.Route.extend({
model: function(params) {
var machine = this.store.find('machine', params.machine_id);
return machine;
},
setupController: function(controller, model) {
this._super(controller, model);
var machinesController = this.controllerFor('machines');
machinesController.set('attrs.currentMachine', model);
}
});
Intuitively, I would think that machine.get('serviceOrders'); would make a call to the API that would be intercepted and handled by Mirage. Which does not seem to be the case

BookshelfJs failing to bring in nested relationship on create

Let's say we have a Join table vehicle_inspections and another join table inspection_actions, as well as basic tables for actions, vehicles, andinspections`.
Lets say I desire the following DB entries:
vehicles
----------------------------
id make
----------------------------
1 Toyota
actions
-------------------------------
id description
-------------------------------
2 Check Tire Pressue
inspections
-------------------------------
id location date
-------------------------------
3 New York tomorrow
vehicle_inspections
--------------------------------
vehicle_id inspection_id
--------------------------------
1 3
inspection_actions
--------------------------------
inspection_id action_id
--------------------------------
3 2
and the following bookshelf classes
inspection_actions.js
(function () {
'use strict';
var Repository = require('../repository');
module.exports = Repository.Model.extend({
tableName: 'inspection_actions',
});
})();
vehicle_inspections.js
(function () {
'use strict';
var Repository = require('../repository');
module.exports = Repository.Model.extend({
tableName = 'vehicle_inspections',
inspection: function () {
return this.belongsTo(require('inspection'));
},
fetchOrCreate: function(vehicleId, inspectionId, options) {
var self = this;
return self.query(function (qb) {
qb.where({
vehicle_id: vehicleId,
inspection_id: inspectionId
});
)}.fetch(options || {}).then(function (model) {
if (!model) {
model.save({
vehicle_id: vehicleId,
inspection_id: inspectionId
});
return model;
};
}
};
});
inspection.js
...
module.exports = Repository.Model.extend(_.extend({
tableName: 'inspections',
actions: function () {
return this.hasMany(require('./inspection-action'));
}
}));
And a route:
new VehicleInspection().fetchOrCreate(req.params.vehicle_id, req.params.inspection_id, {withRelated: ['inspection.actions']})
.then(function (vehicleInspection) {
var inspection = vehicleInspection.related('inspection');
console.log( inspection);
console.log(inspection.related(actions);
})
The inspection console log prints out the correct inspection, however, irrelevantly of what is in the database the second console.log prints out an empty result
{ length: 0,
models: [],
_byId: {},
...
targetIdAttribute: 'id',
foreignKey: undefined,
parentId: undefined,
parentTableName: 'tasks',
parentIdAttribute: 'id',
parentFk: undefined } }
This "bad" behaviour only occurs the first time a projectTasks entry is being created. What appears to be happening is that the inspection_action table is not being populated through the nested withRelated. How could I get this working nested create working?
I'm not completely clear what you are trying to achieve, but here is how I would generally set things up. First I'd create a base model (assuming its saved as base.js), I think you are going to have some problems with circular dependencies, so using the Bookshelf registry plugin would be good:
var config = {
client: // whatever client you are using,
connection: // url to your database
};
var db = require('knex')(config);
var Bookshelf = require('bookshelf')(db);
var Base = Bookshelf.Model.extend({
// Put anything here that will be helpful for your use case
});
Bookshelf.plugin('registry');
Base.model = Bookshelf.model.bind(Bookshelf);
module.exports = Base;
Next create your Vehicle model:
require('inspection');
require('action');
var Base = require('base');
var Vehicle = Base.Model.extend({
tableName = 'vehicles',
inspections: function () {
return this.belongsToMany('Inspection',
'inspections_vehicles', 'vehicle_id', 'inspection_id');
},
actions: function() {
return this.belongsToMany('Action',
'actions_vehicles', 'vehicle_id', 'action_id');
}
};
module.exports = Base.model('Vehicle', Vehicle);
Then an inspection model:
require('vehicle');
var Base = require('base');
var Inspection = Base.Model.extend({
tableName = 'inspection',
vehicles: function () {
return this.belongsToMany('Vehicle',
'inspections_vehicles', 'inspection_id', 'vehicle_id');
}
};
module.exports = Base.model('Inspection', Inspection);
Finally an action model:
var Base = require('base');
var Action = Base.Model.extend({
tableName = 'actions',
};
module.exports = Base.model('Action', Action);
Now assuming that the database isn't already filled in with the data you supplied, we can populate it:
var Inspection = require('inspection');
var Vehicle = require('vehicle');
var Action = require('action');
var toyota;
var newYorkInspection
Vehicle.forge().save({name: 'Toyota'})
.then(function(vehicle) {
toyota = vehicle;
return Inspection.forge().save({location: 'New York', date: 'Tomorrow'});
}).then(function(inspection){
newYorkInspection = inspection;
return toyota.inspections().attach(newYorkInspection);
}).then(function() {
return Action.forge().save({description: 'Check Tire Pressure'});
}).then(function(tirePressureAction) {
return toyota.actions().attach(tirePressureAction);
});
Now I can fetch the toyota vehicle with the related actions and inspections:
var Vehicle = require('vehicle');
return Vehicle.forge({'name': 'Toyota'}).fetch({
withRelated: ['inspections', 'actions']
}).then(function(toyota){
var toyotaInspections = toyota.related('inspections');
var toyotaActions = toyota.related('actions');
});

Control number of objects created in MooTools

Is there a way to count the number of objects created and destroyed in mootools?
Suppose this case:
var Animal = new Class({
initialize: function(){},
create: function() {
alert('created!');
},
destroy: function() {
alert('destroyed');
}
});
var AnimalFactory = new Class({
initialize: function() {
for(i=0;i<10;i++) {
this.add(new Animal());
}
},
add: function(animal) {
this.animalsContainer.push(animal);
},
delete: function(animal) {
this.animalsContainer.remove(animal);
}
});
var animalFactory = new AnimalFactory();
I know how many animals I have created at the beginning but, imagine that somewhere in the code the animal destroy function from a concrete animal instance is called (code not shown here). how can i make the animalContainer array update correctly with one less?
Any help will be much appreciated.
Thanks!!
You can use the Events Class as a mix-in so that it notifies the factory of the animal's demise...
var Animal = new Class({
Implements: [Events,Options], // mixin
initialize: function(options){
this.setOptions(options);
},
create: function() {
alert('created!');
this.fireEvent("create");
},
destroy: function() {
alert('destroyed');
this.fireEvent("destroy", this); // notify the instance
}
});
var AnimalFactory = new Class({
animalsContainer: [],
initialize: function() {
var self = this;
for(i=0;i<10;i++) {
this.add(new Animal({
onDestroy: this.deleteA.bind(this)
}));
}
},
add: function(animal) {
this.animalsContainer.push(animal);
},
deleteA: function(animal) {
this.animalsContainer[this.animalsContainer.indexOf(animal)] = null;
animal = null; // gc
}
});
var foo = new AnimalFactory();
console.log(foo.animalsContainer[0]);
foo.animalsContainer[0].destroy();
console.log(foo.animalsContainer[0]);
watch it run: http://jsfiddle.net/dimitar/57SRR/
this is trying to keep the indexes/length of the array intact in case you save them