ChaplinJS: Referencing a CollectionView property in its template - chaplinjs

I have a Collection in ChaplinJS that has the following initialization code:
Chaplin = require 'chaplin'
Collection = require 'models/base/collection'
Domain = require 'models/domain'
mediator = require 'mediator'
module.exports = class Domains extends Collection
model: Domain
# Initialize the SyncMachine
_(#prototype).extend Chaplin.SyncMachine
initialize: ->
super
#.totalHits = 0
How can I reference totalHits in the template of its view? I am using handlebars templates, and writing {{totalHits}} returns nothing.
Incidentally, shouldn't I be able to rewrite the above code with:
module.exports = class Domains extends Collection
model: Domain
totalHits: 0

Found the solution:
In my CollectionView I can override getTemplateData and pass into it whatever I want, including the complete collection object:
getTemplateData: ->
templateData = super
templateData.collection = #.collection
templateData
Then in the handlebars template I can do {{collection.totalHits}}

Related

Write own Angular2 Annotation

Today, I trying to make my own annotation to use it in Angular2 project.
This annotation must add body class on specific component.
So, I've search on Angular source code, but it's so difficult to see where and how annotation was created.
For the moment, I've tried this :
export function BodyClass(classes: any): ClassDecorator{
classes = classes || {};
if(typeof classes === 'string'){
classes = {classes};
}
return function changeBodyClass(){
console.log('ici');
}
}
And my component :
import {Component} from "angular2/core";
import {RouterOutlet} from "angular2/router";
import {BodyClass} from "../core/annotations/body_class";
#Component({
selector: 'my-component',
template: `
<router-outlet></router-outlet>
`,
})
#BodyClass('test')
export class MyComponent{
}
My console log in the annotation was correctly fired, but I want to use "DOM" class from angular2/src/platform/dom/dom_adapter to add my classes, but DOM in undefined when on console log it (not need to instanciate it).
However, the DOM class works well directly in my component.
I add classes in ngOnInit function, and remove them on ngOnDestroy.
But, I want this behavior on many component, and I think a new annotation is the best way.
Maybe you have a better idea for this ? Or to work with DOM class on a annotation ?
Thanks !
It's not so obvious since you want to work at the component instance level and not at the component class one. So you need to wrap the corresponding constructor function.
export function MyComponentDecorator(value: string) {
return function (target: Function) {
var original = target;
function construct(constructor, args) {
var c : any = function () {
// Call the target constructor
var ret = constructor.apply(this, args);
// Add your additional processing
return ret;
}
c.prototype = constructor.prototype;
return new c();
}
// The new constructor
// Don't forget to add a name at this function
// since Angular requires it for the template compilation
var f : any = function WrappedComponent(...args) {
return construct(original, args);
}
f.prototype = original.prototype;
return f;
}
}
At this point, you wrap the component instance but you lose the component metadata. You need to copy them by hand:
f.prototype = original.prototype;
var annotations = Reflect.getMetadata('annotations', original));
Reflect.defineMetadata('annotations', annotations, f);
var properties = Reflect.getMetadata('propMetadata', original));
Reflect.defineMetadata('propMetadata', properties, f);
return f;
To use this decorator simply add it before or after the #Component one:
#MyComponentDecorator()
#Component({
selector: 'sub',
template: `
<div (click)="showMessage()">Test</div>
`
})
export class SubComponent {
(...)
}
You can notice that this decorator only copies the metadata at the component level and not the other ones like properties (with #Input)...
See this plunkr: https://plnkr.co/edit/PrAvliIpWTNFAtH33bHA?p=preview.

Breeze assumes EntityType is in same namespace as EntityContainer. Shouldn’t Breeze consider if the EntityType value is a qualified type name?

Library: BreezeJS 1.4.11 client-side library
Data Service Adapter: webApiOdata
Remote Service: Web API 2 Implementation of OData v3 without Breeze Controller
I’m working with metadata from a service provider that prefers to keep the EntityContainer in a separate namespace than the EntityTypes it contains. Here are a couple examples similar to our setup:
Default configuration for Web API OData:
http://aspnetwebstack.codeplex.com/workitem/1579
Northwind OData Sample Service:
http://services.odata.org/Northwind/Northwind.svc/$metadata
Consider Breeze’s CsdlMetadataParser.parse function:
var entityTypeName = parseTypeName(entitySet.entityType, schema).typeName;
This function assumes the EntityType has the same schema as the EntityContainer and does not consider the namespace provided in the EntityType attribute of the EntitySet.
A simple Breeze query for the top 10 "Categories" from the Northwind service causes the following error:
Error: Unable to locate a 'Type' by the name: 'Category:#ODataWebV3.Northwind.Model'. Be sure to execute a query or call fetchMetadata first.
Shouldn’t Breeze consider if the EntityType value is a qualified type name and use that rather than assuming the container’s namespace?
Update:
Breeze also assumes that the associations[] for a given navigation property are always in the same schema as the nav property. This causes the following error when attempting to import the metadata for associations in separate namespaces:
"Cannot read property 'end' of null"
The error stems from Breeze's parseCsdlNavProperty and getAssociation functions:
function parseCsdlNavProperty(entityType, csdlProperty, schema) {
var association = getAssociation(csdlProperty, schema);
Replacing this line in Breeze's CsdlMetadataParser.parse method:
var entityTypeName = parseTypeName(entitySet.entityType, schema).typeName;
With this:
var entityTypeName = parseTypeName(entitySet.entityType).typeName;
Resolves the issue and properly considers the namespace inside of the EntityType string. I'd like feedback from Ward or someone else on if this is the right strategy. Also, curious the reasoning behind passing the schema into parseTypeName method, in case removing it will break something else.
Update:
In order to support associations across schemas, I was able to resolve this issue by passing the schemas array all the way from CsdlMetadataParser.parse to getAssociation(). Once getAssociation has access to the schemas array, the following two updates resolve import by removing assumptions and looking at the namespace provided:
function getAssociation(csdlNavProperty, schemas) {
var assocName = parseTypeName(csdlNavProperty.relationship).shortTypeName;
var navSchema = __arrayFirst(schemas, function (sch) {
return sch.namespace === parseTypeName(csdlNavProperty.relationship).namespace;
});
var assocs = navSchema.association;
...
function parseCsdlNavProperty(entityType, csdlProperty, schema, schemas) {
var association = getAssociation(csdlProperty, schemas);
var toEnd = __arrayFirst(association.end, function (assocEnd) {
return assocEnd.role === csdlProperty.toRole;
});
var isScalar = toEnd.multiplicity !== "*";
var dataType = parseTypeName(toEnd.type).typeName;
...
Modifying "getQualifiedTypeName" in breeze.debug.js did the trick for me...
function getQualifiedTypeName(metadataStore, structTypeName, throwIfNotFound)
{
structTypeName = (structTypeName || "") + "";
var shortTypeName = (structTypeName.indexOf(':#') > -1) ?
structTypeName.substring(0, structTypeName.indexOf(':#')) :
structTypeName;
var result = metadataStore._shortNameMap[shortTypeName];
if (result) return result;
if (isQualifiedTypeName(structTypeName)) return structTypeName;
result = metadataStore._shortNameMap[structTypeName];
...
return result;
}
The latest version of breeze is 1.5.3, and a lot of changes have been made since 1.4.11.
I would try that before 'fixing' the CsdlMetadataParser.
This is still an issue in Breeze 1.5.4. I opened
https://github.com/Breeze/breeze.js/issues/96
for it (seems like a bug more than a SO question?).
The workaround I found is to modify the
if (schema) {
line in function parseTypeNameWithSchema(entityTypeName, schema) ( breeze.debug.js line 7327) so that the function is:
// schema is only needed for navProperty type name
function parseTypeNameWithSchema(entityTypeName, schema) {
var result = parseTypeName(entityTypeName);
if (schema && !result.namespace) {
var ns = getNamespaceFor(result.shortTypeName, schema);
if (ns) {
result = makeTypeHash(result.shortTypeName, ns);
}
}
return result;
}
I believe this is the correct behavior, in that if the EntityType name is fully scoped, its namespace should be used; and if the EntityType is name only, the surrounding schema namespace should be used.

How to add instance of the class which satisfies import to CompositionContainer

I am facing the following problem:
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Type1).Assembly));
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Type2).Assembly));
using (CompositionContainer container = new CompositionContainer(catalog))
{
}
I need one more export:
Export[(typeof(Type3))]
The thing is that I can't include an assembly with the class which has this Export attribute. I want to tell the container that:
var myObject = new Type4();
myObject (the instance of Type4) should be exported each time the Import[(typeof(Type3))] is needed. Besides I can't mark Type4 with Export[(typeof(Type3))] and also I want the instance of the class to be used by MEF (so marking this class with Export attribute doesn't work, because I am changing myObject before I pass it to MEF and I want it to be used to satisfy Import).
Then when I try to do:
container.SatisfyImportsOnce(importer);
I expect that MEF will get all the objects from the assemblies in catalog, and for the missing Type3 it will use myObject. This should be the value when I do:
container.GetExportedValue<Type3>();
I spent one day trying different approaches: custom ExporterProvider and some sort of inheritance from Type4 to mark it with proper Export attribute but I can't get it working as I want.
I would be very grateful for help.
Thank you!
Ok, already found an answer.
First problem was that I added 2 the same AssemblyCatalogs to AggregateCatalog - don't do that.
The solution is to use CompositionBatch:
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Type1).Assembly));
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Type2).Assembly));
var myObject = new Type4();
using (CompositionContainer container = new CompositionContainer(catalog))
{
var batch = new CompositionBatch();
Export ex = CreateExport<Type3>(myObject); //Custom implementation
batch.AddExport(ex);
container.Compose(batch);
var val = container.GetExportedValue<Type3>(); //value == myObject
}
Thank you!

Spine.js, setting model default values

There is in rails we have lifecycle hooks, which allows us doing this:
class Subscription < ActiveRecord::Base
before_create :record_signup
private
def record_signup
self.signed_up_on = Date.today
end
end
Is there best way to accomplish same thing (i need it to set some default values) in Spine.js ?
Currently i doing it this way, but maybe there is better way exists ?
class Subscription extends Spine.Model
#record_signup: (self) ->
self.signed_up_on = new Date()
Subscription.bind 'beforeSave', Subscription.record_signup
CoffeeScript class bodies are executable :
class Subscription extends Spine.Model
#record_signup: (self) ->
self.signed_up_on = new Date()
#bind 'beforeSave', #record_signup
How about overriding the standard Model.create function to include your default values if they aren't set?
#create: (atts, options) ->
atts.myVal or= 'someDefault'
record = new #(atts)
record.save(options)

Doctrine_Table Vs class That extends from BaseClass

I am a little confused in this Doctrine model concept , lets say we a table called "article"
Doctrine will generate class called
i am using Zend framework and Doctrine 1.2
models/generated/BaseArticle.php
models/ArticleTable.php
models/Article.php
Is it true to call the ArticleTable in the controller in this way
$tableArticle = Doctrine::getTable('Article');
then to save it in the Article Object like this
$article = new Article();
$fArticles = $tableArticle->getFeaturedArticles();
foreach ($fArticles as $fArticle) {
$article->fromArray($fArticle);
echo $article->title
}
Or I have to let the Article.php to call the ArticleTable ?
then to initiate an Article.php object in the controller ?
class Article extends BaseArticle
{
public function getFArticles()
{
$tableArticle = Doctrine::getTable('Article');
$obj = $tableArticle->getFeaturedArticles();
return $obj;
}
Article.php should not call ArticleTable.php unless really, really needed. In table classes you will only hold queries called by controller like:
$featuredArticles = ArticleTable::getInstance()->getFeatured() ;
Above code is simpler and you will have autocompletion in any IDE.
The reason not to call queries in Article.php is that you will have easier transition to Doctrine2 one day.
For a table call tbl_article or just article, doctrine will generate Article.php and BaseArticle.php. Base classes must not be changed manually.
Article class is where your logic goes. For example, you fetch list of ALL articles in database. When you display them, you want feature articles to have a star (just an example):
controller:
$allArticles = ArticleTable::getInstance()->findAll() ;
template (Smarty version here):
{foreach $allArticles as $article}
{if $article->isFeatured()} <img src=.. some image ..>{/if}
<h5>{$article->title}
{/foreach}
and the model class
class Article extends BaseArticle
{
const STATUS_FEATURED = 1 ;
public function isFeatured()
{
return $this->status == self::STATUS_FEATURED ;
}
}
All these are just some examples, in real life it is much more usefull.
And what are you actually trying to do with this fromArray($fArticle)? I don't see any point of that code.