Dynamic controllers in Ember.js - ember.js

I want to make some dynamic controllers based on the top-level keys of a JSON object where the second level keys become variables for the view. Is this possible?
E.g.
App.dat = { "First": {Var1: "x", Var2: "y"}, "Second": {Var3: "z"}}
I then want to have a FirstController, SecondController, etc. created automatically and then be able to access {{Var1}}, {{Var2}} and {{Var3}} in my view.
The routes work fine:
App.Router.map(function() {
this.route('data');
for(var key in App.dat) {
this.route(key);
}
});
But I can't get the controllers to work. The closest I came was with some hacky eval code:
for(var key in App.dat) {
console.log("App." + key + "Controller = Ember.Controller.extend();");
eval("App." + key + "Controller = Ember.Controller.extend();");
Ember.$.each(eval("App.dat."+key), function(kkey,v) {
console.log("App." + key + "Controller." + kkey + " = '" + v + "';");
eval("App." + key + "Controller." + kkey + " = '" + v + "';");
});
}
That results in the following evaluations:
App.FirstController = Ember.Controller.extend();
App.FirstController.Var1 = "x";
App.FirstController.Var2 = "y";
App.SecondController = Ember.Controller.extend();
App.FirstController.Var2 = "z";
But I'm clearly missing something because I can't access {{x}},{{y}} or {{z}} from the view. I am aware the correct way to instantiate variables for the view is with a constructor object like:
App.FirstController = Ember.Controller.extend({Var1: "x", Var2: "y"});
But that isn't practical and I can't figure out where the constructor object gets stored.
Thanks in advance.

You can override Ember.DefaultResolver's resolveController method. Which is responsible for lookuping controller classes.
App = Ember.Application.create({
Resolver: Ember.DefaultResolver.extend({
resolveController: function(parsedName) {
var props = Ember.get(App.dat, parsedName.name);
if (!Ember.isNone(props)){
return Ember.Controller.extend(props);
}
return this._super(parsedName);
}
})
});
jsbin

After some careful bug hunting, the following code works fine:
for(var key in App.dat) {
properties = Array();
Ember.$.each(eval("App.dat."+key), function(kkey,v) {
properties.push(kkey + ": '" + v + "'")
});
console.log("App." + key + "Controller = Ember.ObjectController.extend({" +properties + "})");
eval("App." + key + "Controller = Ember.ObjectController.extend({"+ properties + "})");
}
Is there a less hacky way to do this than by eval()ing everything? Remember this data comes from JSON, so I can't imagine this would be safe in a real app.

Related

Postman send request entirely constructed in pre-requisite script

I have this below piece of code that generates me multiple orders in Pre-request Script section.
I dont need to have anything in "Body" section. But sending just [{}] in the body gives me 400 error.
var guid = (function() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return function() {
return 'HolCal' + s4() + '-' + s4() + '-' + s4() + '-' +
s4();
};
})();
var requestKeyNum = 2;
var orders = [];
for (var i = 0; i < requestKeyNum; i++) {
var key = guid();
orders.push({
"key": key,
"tradeDate": "2019-07-03",
"settleDate": "2019-07-04",
"transactionCode": "B",
"fundingCurrencySecurity" :{
"secId":1894823,
"secType1": "CASH",
"secType2":"NA",
"secType3":"NA",
"secType4":"NA",
"assetClass":"C",
"exchangeCode":"",
"tradeCurrencyCode":"USD",
"maturityDate":null,
"mortgageClass":null,
"investIdType":"D",
"investId":"9999USD",
"clearingHouseCode":null,
"settlementLocation":"PHY",
"expirationDate":null,
"issueCountry":""
}
})
}
postman.setEnvironmentVariable("orders", JSON.stringify(orders));
How must your generated body look like?
I assume, that you want so send you generated orders in your body.
If its true, you must reference to the orders variable in your body. Use {{orders}} in your body panel to do this.

django admin custom time widget

I am trying to override django's time widget.
if (!$) {
$ = django.jQuery;
}
function overrideTimeOptions() {
$('.timelist').each(function(num, el) {
var time_format = '%H:%M';
$(el).html('');
for (var i=1; i<25; i++) {
var time = new Date(1970,1,1,i,0,0);
console.log(time)
var lnk = "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", '" + time.strftime(time_format) + "');"
console.log("this is link");
console.log(lnk);
$(el).append('<li>' + time.strftime(time_format) + '</li>');
}
});
}
setTimeout(function(){overrideTimeOptions()},500);
Here I can see the time options but when I click the time it gives me some weired value in the input field like NaNaNa
Can anyone help me on this whats going on here ??

extending EmberDefaultResolver with Ember-App-Kit

I'm making a custom resolver based on the pattern below from Robin Ward [ video / 15sec]
which is a trick to have a mobile device look for "mob_template.hbs" first before loading "template.hbs"
App.Resolver = EmberDefaultResolver.extend({
resolveTemplate: function(parsedName){
var t = this._super(parsedName);
if App.mobileActive){
return this._super('mob_' + parsedName) || t;
}
return t;
}
});
However I'm using Ember App Kit, which uses a special version of the resolver:
I can't really tell what's going on in there or what I would need to do to produce similar functionality. Anyone have any idea?
I've tried something like this but it results in nothing being resolved:
var App = Ember.Application.extend({
//...
Resolver: Ember.DefaultResolver.extend({
resolve: function(fullName) {
var parsedName = this.parseName(fullName),
resolveMethodName = parsedName.resolveMethodName;
if (!(parsedName.name && parsedName.type)) {
throw new TypeError("Invalid fullName: `" + fullName + "`, must be of the form `type:name` ");
}
if (this[resolveMethodName]) {
if (window.screen_type == 'mobile'){
var resolved = this[resolveMethodName](parsedName + '_mobile');
} else{
var resolved = this[resolveMethodName](parsedName);
}
if (resolved) { return resolved; }
}
return this.resolveOther(parsedName);
},
})
});
Apparently parsedName is not a string of the template name in the EAK resolver, it has some props representing the template name though, parsedName.fullNameWithoutType being the one to target:
var CustomResolver = Resolver.extend({
resolveTemplate: function(parsedName){
var resolve = this._super(parsedName);
if (['foo','bar'].indexOf(window.special_prop) > -1){
var orig__parsedName_name = parsedName.name;
parsedName.name = parsedName.name + '_' + window.special_prop;
parsedName.fullName = parsedName.fullName + '_' + window.special_prop;
parsedName.fullNameWithoutType = parsedName.fullNameWithoutType + '_' + window.special_prop;
resolve = this._super(parsedName) || resolve;
}
return resolve;
} });
var App = Ember.Application.extend({ //... Resolver: CustomResolver });

#each iteration number in Ember.js or {{#index}}

According to this question, it was possible to do something like this with Handlebars rc1:
{{#each links}}
<li>{{#index}} - {{url}}</li>
{{/each}}
{{#index}} would basically give you the iteration index, which is really useful when creating tables.
When I try this with Ember.js rc3, I get an unexpected token error. Does this not work anymore? Did it ever work? Is there another way to get the iteration index?
It looks like it was possible. Can't get it to work with HBS RC3. Probably, is deprecated.
Here's a "hand written" HBS helper.
This can help you gettin the index with {{index}} and side by side you can know if the iteration in on first or last object of the Array with {{first}} and {{last}} respectively.
Ember.Handlebars.registerHelper("foreach", function(path, options) {
var ctx;
var helperName = 'foreach';
if (arguments.length === 4) {
Ember.assert("If you pass more than one argument to the foreach helper, it must be in the form #foreach foo in bar", arguments[1] === "in");
var keywordName = arguments[0];
options = arguments[3];
path = arguments[2];
helperName += ' ' + keywordName + ' in ' + path;
if (path === '') {
path = "this";
}
options.hash.keyword = keywordName;
} else if (arguments.length === 1) {
options = path;
path = 'this';
} else {
helperName += ' ' + path;
}
options.hash.dataSourceBinding = path;
// Set up emptyView as a metamorph with no tag
//options.hash.emptyViewClass = Ember._MetamorphView;
// can't rely on this default behavior when use strict
ctx = this || window;
var len = options.contexts[0][path].length;
options.helperName = options.helperName || helperName;
options.contexts[0][path].map(function(item, index) {
item.index = index;
item.first = index === 0;
item.last = index === len - 1;
})
if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) {
new GroupedEach(ctx, path, options).render();
} else {
return Ember.Handlebars.helpers.collection.call(ctx, Ember.Handlebars.EachView, options);
}
});
and this can be tested like
{{#foreach array}}
{{log index first last}}
{{/foreach}}
i had the same problem recently i finish by writing a bound helper and passing them objects via Binding for example item here is an ember DS.Store object and content is a 'content' of the controller. hope it
Ember.Handlebars.registerBoundHelper 'isPair', (content, options)->
item = options.hash.item
content_name = options.hash.content || 'content'
if #get(content_name).indexOf(item) % 2 == 0 then 'is-pair' else 'is-unpair'
and in you view you call it
{{isPair content itemBinding='order'}}
i don't know if it is what you looking for but it might give you some ideas how to use it in your project.
btw. Ember overwrites #each helper that's why there it no #index i suppose

Google Friend Connect fcauth cookie in php

this may be easy for most of you .. but not me.
I am using some "sample" Google code - as it fits my purpose so why change what works - but for the life of me I cannot access/find/get etc the FCAuth cookie after a user is logged in.
Help please - thanks in advance.
Here is my code (the Site ID is in a set variable, and all the calls work todate. just need to find/get the FCAuth cookie.
var viewer, ownerFriends, activities;
google.friendconnect.container.setParentUrl('/api/' /* location of rpc_relay.html and canvas.html */);
google.friendconnect.container.loadOpenSocialApi({
site: SITE_ID,
onload: function() { initAllData(); }});
function initAllData() {
var params = {};
params[opensocial.DataRequest.PeopleRequestFields.PROFILE_DETAILS] =
[opensocial.Person.Field.ID,opensocial.Person.Field.NAME,opensocial.Person.Field.THUMBNAIL_URL,opensocial.Person.Field.PROFILE_URL];
var req = opensocial.newDataRequest();
req.add(req.newFetchPersonRequest('VIEWER', params), 'viewer');
req.add(req.newFetchPeopleRequest(
new opensocial.IdSpec({'userId' : 'OWNER', 'groupId' : 'FRIENDS'}), params),
'ownerFriends');
req.add(req.newFetchActivitiesRequest(new opensocial.IdSpec({'userId' : 'OWNER', 'groupId' : 'FRIENDS'})), 'activities');
var idspec = new opensocial.IdSpec({ 'userId' : 'VIEWER','groupId' : 'FRIENDS' });
req.add(req.newFetchPeopleRequest(idspec), 'viewer_friends');
req.send(onData);
req.send(setupData);
};
function setupData(data) {
ownerFriends = data.get('ownerFriends').getData().asArray();
var html = "";
for (var i = 0; i < ownerFriends.length && i < 8; i++) {
var person = ownerFriends[i];
html += "<a title='" + person.getField("displayName") + "' href='" + person.getField("profileUrl") + "'>";
html += "<img class='memberPhoto' src='" + person.getField("thumbnailUrl") + "' width='50px' alt='" + person.getField("displayName") + "'/>";
html += "</a> ";
};
document.getElementById('members').innerHTML = html;
viewer = data.get('viewer').getData();
if (viewer) {
document.getElementById('memberstate').innerHTML =
'<h2>' + viewer.getField("displayName") + ' welcome to the Yoga Council of Canada </h2>' ;
} else {
document.getElementById('memberstate').innerHTML =
'<h2>Join with one click</h2> After joining, you will automatically appear as a recent member.';
}
viewer = data.get('viewer').getData();
if (viewer) {
document.getElementById('profile').innerHTML =
'<img align="left" src="' + viewer.getField("thumbnailUrl") + '" style="margin-right: 20px;" >' +
'<strong>' + viewer.getField("displayName") + '</strong><br>' +
'Settings<br>' +
'Invite a friend<br>' +
'Sign out<br>';
} else {
google.friendconnect.renderSignInButton({ 'id': 'profile' });
}
};
function onData(data) {
if (!data.get("viewer_friends").hadError()) {
var site_friends = data.get("viewer_friends").getData();
var list = document.getElementById("friends-list");
list.innerHTML = "";
site_friends.each(function(friend) {
list.innerHTML += "<li>" + friend.getDisplayName() + "</li>";
});
}
};
OK, I am/was being totally thick, the cookie is automatically set as
$_COOKIE['fcauth<your appID>'];
So you can "just call it" i.e.
<?php if($_COOKIE['fcauth<your appID>']): do something endif; ?>