Are single-lettered word models supported in EmberJS? - javascript

I cannot really pinpoint whether the issue is with Ember or Ember data, or if it's even an issue, but here's what happens:
Let's say you've got your model called tell_me_a_story. This will be the name that your JSON should provide, should you be using ActiveModelAdapter.
Regardless, when Ember or Ember Data process it internally, it'll camelize it and it becomes tellMeAStory, correctly indicating that "A" and "Story" are two separate words.
However, when internally it is decamelized to lookup for the model, the decamelize function will convert it into tell_me_astory.
This final behavior seems flawed to me, but when looking at the tests that derived this behavior, it is actually intended to manage acronyms in that fashion. (Compare the following example with the "innerHtml" that I would expect for camel casing multi-letter acronyms.)
QUnit.test("converts a camelized string into all lower case separated by underscores.", function() {
deepEqual(decamelize('innerHTML'), 'inner_html');
if (Ember.EXTEND_PROTOTYPES) {
deepEqual('innerHTML'.decamelize(), 'inner_html');
}
});
(Source in Ember Runtime)
So, which is the correct way to use single-letter words in models with Ember? Are they even supported?
Here's an example of what I'm trying to do:
// this comes from a separate data source, e.g. REST APIs
var myModelName = 'tell_me_a_story';
// this line will throw if the model file is named "tell-me-a-story"
if (!store.getById(myModelName, 1)) {
// this line will throw if the model file is named "tell-me-astory"
store.pushPayload(myModelName, myObject);
}

You can override the stores _normalizeTypeKey then alter the camelCase behaviour to become what you want (e.g. dasherized or just fix this one case).
You can also override the serialisers typeForRoot when going the other way - this lets you tell ember what the model key is (e.g. tellMeAStory) for a particular key in your data (e.g. tell_me_a_story).
It appears there is work underway to make everything work like the container does (which is dasherized)

Related

How do I pass an Eloquent model to a Knockout.js view model constructor?

I have a solution (see below), but it's awkward and klunky & I'd like to hear how others have solved this problem.
Here's a simple example to illustrate the problem:
Imagine I have an Eloquent User model and I'm putting together an "edit user" page that uses Knockout to handle value-to-DOM-element bindings.
In my controller method for this page, I'm doing the following:
public function getEditUser($id = null)
{
return View::make("account.edituser")
->with("user", User::find($id))
->with("groups", Group::all());
}
where the Group model is for my access control groups. The user can be a member of zero or more groups and the relationship is set up in the normal way for Eloquent models.
In the template, I have a bunch of elements (text, select, radio buttons, etc.) set up with data-bind attributes to bind my Knockout view model to the elements.
In the <script> portion of the page, I have the following:
var createUserViewModel = function (user, groups) {
return {
id: ko.observable(user.id),
name: ko.observable(user.name),
groups: ko.observableArray(user.groups),
// ...other attributes go here
// the list of available groups
availableGroups: ko.observableArray(groups)
};
};
// instantiate the view model
var viewModel = createUserViewModel(
// note that I'm using Smarty for my templating system. The
// lines below apply the json_encode method and disable the
// htmlspecialchars function which I have set up to encode
// all output by default
{$user|json_encode nofilter},
{$groups|json_encode nofilter}
);
ko.applyBindings(viewModel);
The user argument to the createUserViewModel function will be JSON-encoded, so it will look like this: { id: 1234, name: "Joe Smith", groups: ['group1', 'group2'], ...}
This is a simple example: I have several forms for entering other information which are significantly more complicated than this.
There are a couple of problems with this:
As I said, it's awkward. The source generated by this is difficult to read for larger models.
I suspect there's an XSS vulnerability here, since I'm echoing data via json_encode directly into the body of the script element. I haven't been able to exploit this, but I think someone else could find a way.
But I can't think of another way to do it that doesn't radically change the way the application works (ie. use AJAX calls to retrieve the data).
Can anyone share a better way to do this?
Re (1) you need to look at the very useful mapping which is designed for exactly this - http://knockoutjs.com/documentation/plugins-mapping.html ... this will replace the createUserViewModel function for you, and save you having to manually turn a JSON object into something observable.
Re (2) I'm not expert enough with security and XSS to give an authoritative answer, but it looks OK to me. So long as the user and group data was sanitised before you stored it, then it should be OK to echo it back as JSON. If you're not providing a textbox or other input for a user to type into that then affects this data then there's no angle for an attacker to inject a malicious script. Plus JSON-encoding itself is quite a good sanitisation, in that any JavaScript will just end up as a string. So to be sure, given:
{$user|json_encode nofilter}
will print out some JSON, you could immediately try JSON.parse on it:
var user = JSON.parse({$user|json_encode nofilter})
before you then do anything with it in your script.

Angular input model conditionally reads from one property, writes to another

I have a Person class where edits made to the person must be verified by an admin user.
Each attribute has an "approved" and "tmp" version. Sometimes the "tmp" version is not set:
person = {first:'Bob', firstTmp:'Robert', last:'Dobbs', lastTmp:undefined}
When displaying the person, I want to display the "tmp" value if it is set, otherwise display the "approved" value. When writing, I want to write to the "tmp" value (unless logged in as an admin).
Ideally, this would not require a lot of custom markup, nor writing cover methods for each property (there are around 100 of them). Something like this would be nice:
<input ng-model="person.first"
tmp-model="person.firstTmp"
bypass-tmp="session.user.isAdmin" />
When displaying the value, display the tmp value if it is defined. Otherwise display the approved value.
When writing the value, write to the tmp value, unless logged in as an admin. Admins write directly to the approved value.
What's a good clean way to implement this in Angular?
Extend NgModelController somehow?
Use a filter/directive on the input?
Cover methods?
Just do the writing server-side?
I will try to go through your options one by one:
Extend NgModelController somehow?
I don't think this is a good idea. It won't be nice if something goes wrong and you don't know if you can even rely on something as basic as ng-model
Just do the writing server-side?
This would seem like the easier way (if you already know or find it easy to manage it in the back end), although the interaction would need a new request to the server.
Use a filter/directive on the input?
I believe this would be the best way to do it, as it is easy to understand what is going on by just taking a look at the markup. It's angular, you already know that some property like tmp-model is extending the markup.
Cover methods?
This would also be easy to implement, and you would be implementing some sort of "business logic" as a validator in your cover method.
Given that I've extended a bit in my answer, I can give you an inline example of the last one.
<input ng-model="person.firstTmp"
ng-init="person.firstTmp = person.firstTmp || person.first"
ng-change="updateProperty(person, 'first')" />
And on the controller, you could do something like:
$scope.updateProperty = function(person, propertyName) {
// The temporary property has already been changed, update the original one.
if($scope.session.user.isAdmin)
person[propertyName] = person[propertyName + 'Tmp'];
}

Better design for data stored using HTML5 localStorage

I have a scenario on my web application and I would like suggestions on how I could better design it.
I have to steps on my application: Collection and Analysis.
When there is a collection happening, the user needs to keep informed that this collection is going on, and the same with the analysis. The system also shows the 10 last collection and analysis performed by the user.
When the user is interacting with the system, the collections and analysis in progress (and, therefore, the last collections/analysis) keep changing very frequently. So, after considering different ways of storing these informations in order to display them properly, as they are so dynamic, I chose to use HTML5's localStorage, and I am doing everything with JavaScript.
Here is how they are stored:
Collection in Progress: (set by a function called addItem that receives ITEMNAME)
Key: c_ITEMNAME_Storage
Value: c_ITEMNAME
Collection Finished or Error: (set by a function called editItem that also receives ITEMNAME and changes the value of the corresponding key)
Key: c_ITEMNAME_Storage
Value: c_Finished_ITEMNAME or c_Error_ITEMNAME
Collection in the 10 last Collections (set by a function called addItemLastCollections that receives ITEMNAME and prepares the key with the current date and time)
Key: ORDERNUMBER_c_ITEMNAME_DATE_TIME
Value: c_ITEMNAME
Note: The order number is from 0 to 9, and when each collection finishes, it receives the number 0. At the same time, the number 9 is deleted when the addItemLastCollections function is called.
For the analysis is pretty much the same, the only thing that changes is that the "c" becomes an "a".
Anyway, I guess you understood the idea, but if anything is unclear, let me know.
What I want is opinions and suggestions of other approaches, as I am considering this inefficient and impractical, even though it is working fine. I want something easily maintained. I think that sticking with localStorage is probably the best, but not this way. I am not very familiar with the use of Design Patterns in JavaScript, although I use some of them very frequently in Java. If anyone can give me a hand with that, it would be good.
EDIT:
It is a bit hard even for me to explain exactly why I feel it is inefficient. I guess the main reason is because for each case (Progress, Finished, Error, Last Collections) I have to call a method and modify the String (adding underline and more information), and for me to access any data (let's say, the name or the date) of each one of them I need to test to see which case is it and then keep using split( _ ). I know this is not very straightforward but I guess that this whole approach could be better designed. As I am working alone on this part of the software, I don't have anyone that I can discuss things with, so I thought here would be a good place to exchange ideas :)
Thanks in advance!
Not exactly sure what you are looking for. Generally I use localStorage just to store stringified versions of objects that fit my application. Rather than setting up all sorts of different keys for each variable within localStore, I just dump stringified versions of my object into one key in localStorage. That way the data is the same structure whether it comes from server as JSON or I pull it from local.
You can quickly save or retrieve deeply nested objects/arrays using JSON.stringify( object) and JSON.parse( 'string from store');
Example:
My App Object as sent from server as JSON( I realize this isn't proper quoted JSON)
var data={ foo: {bar:[1,2,3], baz:[4,5,6,7]},
foo2: {bar:[1,2,3], baz:[4,5,6,7]}
}
saveObjLocal( 'app_analysis', data);
function saveObjLocal( key, obj){
localStorage.set( key, JSON.stringify(obj)
}
function getlocalObj( key){
return JSON.parse( localStorage.get(key) );
}
var analysisObj= =getlocalObj('app_analysis');
alert( analysisObj.foo.bar[2])

Checking for any dirty Backbone model data within collection

I have a requirement to "nag" a user about unsaved changes when they switch between different Backbone collection models (by clicking on a table row). I've googled for "check backbone model dirty data" (for instance) and not found anything definitive.
I accomplished this using underscore's "some" and isEqual functionality, in a manner such as the following, "some()" being sufficient to determine if there are any un-saved changes (as opposed to what those precise changes might be), in particular because the model attribute is actually an array of objects.
var anyDirty = _.some(myCollection.models, function(model) {
return !_.isEqual(model.get('nodes'), model.previousAttributes()['nodes]);
});
I am new to Backbone and am wondering if this is an accepted sort of approach for adhoc checking for dirty model data. Or, does Backbone provide some sort of built in functionality for this purpose, that my initial attempts at googling did not reveal?
I have another attribute I need to monitor in addition to 'nodes', so I'm switching to using changedAttributes(): http://backbonejs.org/#Model-changedAttributes:
var anyDirty = _.some(myCollection.models, function(model) {
return model.changedAttributes();
});
What may make this an imperfect solution is that it seems like it will return an object of changedAttributes even if the attribute got changed back to it's original value. So it almost seems that what I need in the long run is to take a snapshot of the original data and compare against that. Still though, using model.changedAttributes() is a more concise alternative to what I first posted.

Approach to unit-testing large batches of dynamically generated strings

My web app has a class for analysing and manipulating the data stored in the URL's hash, which look something like
http://myapp.com/#!/location/hornsea/season/spring/facilities/+shop+swimming-airport/size/50
To be able to unit test the various permutations I'm storing some URL fragments in an object (e.g.
var fragments {
valid: ["/location/hornsea", "/season/winter","/size/50"],
invalid: ["location/hornsea", "/seasonwinter","/size/fifty"]
}
And then before runing my tests I dynamically build all possible valid and invalid urls and then loop through these, adding a test for each url.
This is fine when I'm running a test for validity of the url, as I just check for true or false in my isValid() method, but when testing for getting the parameters from the URL I don't know how to approach the problem - I have to compare the returned value (e.g. {location: "hornsea""}) with the expected value, but as the string to be analysed is dynamically constructed before running the test I don't have the expected value stored anywhere.
Now, I'm not sure if my approach is overkill - should I care about testing all methods on all possible url structures? Could I set up tests that run against all possible urls when it's easy to do so, but run against a more manageable subset when I need to have finer control over the tests, and yet still manage to cover all eventualities. i.e. could I write a test suite where testing
http://myapp.com/season/autumn
is adequate enough to cover examples such as the following too.
http://myapp.com/location/dungeness/season/autumn
http://myapp.com/location/camberwell/seasonautumn
And how could I be sure that I haven't left any gaps? Are there any general approaches to this sort of problem, or is it something very specific to the particular application?
You can test this with an inverse function test. You have to write a function (encode) that's the inverse function to your URL parser. The encode function constructs the URL from the valid input values. The test has the form:
input = {"location" : "hornsea", "season" : "winter", "size" : "50"}
assert input == parse(encode(input))
To get a good best coverage you can use one of the Quickcheck implementations to generate the input values. With generated values you can create subsets of the valid input parameter or shuffle parameters.

Categories