angular design a compare directive - angularjs

I'm planning to write a angular directive that will compare two object (primitive type and object type).
my plan is:
write a primitiveCompare directive that compares primitive type and return something like this:
<primitiveCompare left="" right="" settings=""></primitiveCompare>
write a objectCompare directive that compares object type and return something similar:
<objectCompare left="" right="" settings=""></objectCompare>
inside objectCompare directive, I'm thinking to loop the object's keys and create a template dynamically, it would be something like:
Object.keys(left).forEach(function(key){
if(typeOf key !== 'object'){
html = html + '<primitiveCompare left='left[key]' right='right[key] settings=''> </primitiveCompare>
else html = html + '<primitiveObject left='left[key]' right='right[key] settings=''> </primitiveObject>
Would above design work well, is no, can you point out better solutions?
Thanks in advanced!

Related

Detect array in angular template

I have an array that I am iterating through and displaying. Sometimes, however, the item it finds is an array. I'd like to do something different with this, using an ng-if. I am unsure how to do this easily. It seems like a common issue but there doesn't appear to be an easy solution.
You can use Angular.isArray() (see doc) but it does not exist as a already defined filter so you might need to define your own.
Something like that :
angular.module('...', []).filter('isArray', function() {
return function (input) {
return angular.isArray(input);
};
});
And then in your template usimply use {{ myVar | isArray }}.
My only concerne is ... is it really clean to do so ? I don't know but this will solve your problem.
By the way, was already asked on StakcOverFlow : Angular expression to check if model is array or object

How to create an angular filter that outputs a unique ID

The question is quite simple, How can you create an angularJs filter that will concatenate any input to a unique ID. This can be very useful for generating HTML id's, or to define unique attribute values for a group of elements in a ng-repeat.
NOTE: The ID must be 'globally' unique which makes angular ng-repeat's $index useless.
Now, the solution that probably comes to your mind is something like this:
myModule.filter('uniqueId', function(){
var idCounter = 0;
return function(input) {
return (input || '') + (++idCounter);
};
});
and in your HTML you write something like:
<div id="{{groupName | uniqueId}}">
The challenge is that angular will run into a digest loop, because evaluating groupName | uniqueId will never yield the same value which means the scope will never settle.
One last thing. We use angular v1.2.27 which means we can't use angular 1.3's new :: (i.e. one time binding) operator.
if you can bind to an object instead of an individual property you could do something like the following:
check the object for the unique value. if present return it. if not present generate one, assign it and return it.
myModule.filter('uniqueId', function(){
var idCounter = 0;
return function(input) {
return input.$$uniqueValue || (input.$$uniqueValue = ++idCounter);
};
});
Not sure if this exactly fixes you problem but I hope it helps.

What does the "type" attribute of a directive do?

What does the "type" attribute of a directive do? I can't seem to find it documented.
Here's an example of its usage:
https://github.com/crudbetter/angular-charts/blob/master/src/piechart.js#L81
Does that usage just create an unused attribute, or does it actually have some sort of meaning?
The type attribute governs how the template is wrapped. Specifically, if it is svg or math it is wrapped in a div and a sub element of the type. Here is the function that leverages it inside the $compile service where the directive API lives from the source:
function wrapTemplate(type, template) {
type = lowercase(type || 'html');
switch (type) {
case 'svg':
case 'math':
var wrapper = document.createElement('div');
wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
return wrapper.childNodes[0].childNodes;
default:
return template;
}
}
It's now known as templateNamespace, and described as such in the docs.
As far as the AngularJS Directive Definition Object documentation goes, there is no mention to a "type" attribute whatsoever.
In the source you provided, they use the value 'SVG'. The only related attribute would be templateNamespace which corresponds to the document type used by the markup in the template.
AngularJS needs this information as those elements need to be created and cloned in a special way when they are defined outside their usual containers like <svg> and <math>.
Edit:
Well, I tried finding out if type works like templateNamespace but couldn't make any of them work (tried with Angular v1.3.2 and v1.2.1).
here's the fiddle

how can I bind an input to a property deep within a complicated data structure?

I have an angular-rails resource with a property that consists of irregular data that is potentially quite complicated-- something like:
{ foo: [ { bar: 'baz', lol: [ { 'omg': ... etc
I built a directive which takes this data and drills down into it, dynamically rendering form fields for each object... I've got the data displaying perfectly, however the piece of the puzzle that's missing is, how can I take advantage of Angular's binding so that changing the value on the form input will actually update that attribute in the model?
Originally I was thinking this should be simple, as my code drills through the data structure, it can just be maintaining a path, so I'd end up with something like: 'myObject.foo.bar'
Then I could just pass that to the form input's ng-model attribute...... however, I could not get angular to recognize ng-model="path" where $scope.path = "myObject.foo.bar"... ng-model="{{path}}" did not work either.
My directive is using angular.forEach to drill down into this datastructure, and someone had mentioned to me that I should perhaps be using ng-repeat instead, but I wasn't sure if this is the correct way to go or not? I still feel like there should just be a way to do ng-model="path" and have that work...
Any guidance would be greatly appreciated.
To use dynamic property names, use array notation. I.e. myObject["foo"]["bar"]. Plunkr: http://plnkr.co/edit/W60F75?p=preview
Can you try setting an property on the scope with the value of the object itself and then refer it in the form element? Like below:
// In your script
$scope.obj = myObject;
// In your form
<input ng-model="obj.foo.bar" type="text" />

Backbone, JST, EJS: Blank values in templates

I have a JST-->EJS backbone template for a 'projects' form. Ideally, I'd like to use the same template for both creating and editing models.
At the moment, I have something such as this in the template:
<input type='text' name='demo_field' value='<%= demo_field %>' />
That works fine so long as demo_field has a value, but if it doesn't, the whole form fails with an uncaught referenceError.
So, what's the most elegant way to assure variable fields return blank, instead of fail, in Backbone...or JST...or EJS?
Cheers...
I'd probably make a helper, since javascript doesn't have any nice way of doing something like
field if field? in CoffeeScript.
Throw something like this into a helper function:
function printIfExists(field) {
return (typeof field !== "undefined" && field !== null) ? field : '';
}
and call it in your templates. Easy as pie!
You might also want to use the alternate function declaration:
var printIfExists = function(field){...}
I've been using coffeescript so long I can't recall why... scoping issues with the former example, probably.

Resources