Using JSON square bracket notation within Angular directives to access values - angularjs

I have a JSON object that contains namespaces in some of its keys in the form of namespace:key. Because of this, I need to use the square bracket notation instead of the dot notation to access its value.
I am trying to use some angular directives/filters to work with the data, in this example I will be using filter, but the issue seems transversal to the use of bracket notation within the directives as well.
Here's my example:
ng-repeat with filter in HTML:
<ul>
<li ng-repeat="item in items | filter:{properties['namespace:status']}">
{{item.name}}
</li>
</ul>
$scope.items content:
{
"properties":{
"namespace:status":"A",
"name":"Potato",
// ...
},
// ...
},
{
"properties":{
"namespace:status":"B",
"name":"Carrot",
// ...
},
// ...
},
{
"properties":{
// Note that it doesn't contain the namespace attribute
"name":"Bean",
// ...
},
// ...
}
Expected rendered HTML:
<ul>
<li>Potato</li>
<li>Carrot</li>
</ul>
Actual outcome
Error: [$parse:syntax] Syntax Error: Token '[' is unexpected, expecting [:] at column X of the expression [items | filter:{properties['namespace:status']}] starting at [['namespace:status']}].
directing me to a syntax error.
My issue is that the same expression {{properties['namespace:status']}} does fits the syntax in templates, so I'm not sure I am doing something wrong, or if the directives simply can't handle the bracket notation.
If its the latter, any suggestions on how I could approach this without rewriting the JSON?

You should specify an object key like that
<ul>
<li ng-repeat="item in items | filter:{prop: properties['namespace:status']}">
{{item.name}}
</li>
</ul>
Here you can check http://codepen.io/anon/pen/BslpA
But you should know that angularjs can not filter by array of object properties, it can be only array.

Related

Replace values from json

I display data from a json.
I want replace values from an other (for translation).
It's like :
<li ng-repeat="childrens in data.children track by $index">
<a>{{childrens.type}}</a>
</li>
In 'type' I can have "QUOTE", "BILL" or "DEPOSIT"...
And I want replace this value with the translation.
But I'm beginner in angular, and i work on json for the first time as well, what's the better way to do this ?
I tried to use the fonction replace() in my controller but that doesnt work :
if($scope.children.type =='QUOTE'){
$scope.children.type = $scope.children.type.replace('Facture');
}
Thanks for your help guys :)
You can do this:
<li ng-repeat="childrens in data.children track by $index">
<a>{{mapObject[childrens.type].text}}</a>
</li>
In Controller you can use javascript map
$scope.mapObject = {
"QUOTE":{
"text":"Facture"
}
}

Adding filter to ng-repeat

I'm currently making a front-end with Angular.
I have a JSON file like following:
{
"groups": [
group1: {
"part":1
},
group2: {
"part":2
}
]
}
And I have lists like following:
<li ng-class="{active: section >= {{group.number}}}" ng-bind="group.title" ng-repeat="group in groups" ></li>
Let's say there are 100 groups in my JSON file. If I want to only show groups with "part":1, how do I add this filter in ng-repeat?
You can pass an object to filter with the key/value you want to filter on:
ng-repeat="group in groups | filter:{part:1}"
try this
ng-repeat="group in groups | filter:{'part': 1}:true"
from official documentation
In HTML Template Binding
{{ filter_expression | filter : expression :
comparator}}
for comparator value if its true
true: A shorthand for function(actual, expected) { return
angular.equals(actual, expected)}. This is essentially strict
comparison of expected and actual.
this gives you the exact match
Consider also passing a function rather than Object into filter (which may work this time, but not all things are easily expressible in a readable fashion directly in the view):
ng-repeat="group in groups | filter:functionOnScope"
The | pipe operates on the thing to the left groups, so filter is a function whose first argument receives groups and whose subsequent arguments appear after the :. You could visualize a | b:c:d | e as e(b(a,c,d)) - once I realized that I used filters more for simple things.
So the second argument filter receives is a predicate (function that takes in something and returns true or false to operate on each element - like a SQL WHERE clause) inside groups. Filters are super useful - if you have quick logic or transformations you want to do in the view (and you don't need to test it) then they can make your controllers and directives more succinct. (So instead of ng-if="collection[collection.length - 1].length > 0" you could write ng-if="collection | last | some", which is much more readable.)
If you have complicated logic, it may be better to put in a controller or directive instead of the view (this is also easier to unit test that way if you care about it) - if it's in the view you need something like PhantomJS at a minimum to emulate the DOM. Assuming you bound some dynamicallySelectedPart on the $scope to 1, 2, etc. maybe as an ng-model on a <select /> so the user can select it, then you can just write this to keep it dynamically up-to-date.
$scope.functionOnScope = function (elementInGroups) {
// Maybe do a check like:
// if ($scope.dynamicallySelectedPart === elementInGroups.part) {
return true;
// }
// Some other logic...
return false;
};
Your JSON looks malformed in that you have an array with key-value pairs.
Below is some code that should work. I am using the Controller ViewAs syntax.
HTML
<div ng-app="MyApp">
<div ng-controller="MyController as me">
{{me.greeting}}
<ul>
<li ng-repeat="group in me.groups | filter:{'part': 1}:true">
{{group}}
</li>
</ul>
</div>
JS
var myApp = angular.module('MyApp',[]);
myApp.controller('MyController', function() {
this.greeting = 'Hola!';
this.groups = [ {id: 'group1', "part":1 }, {id: 'group2', "part":2 } ];
});
Code Pen Here

Efficient way to bind Json to Html?

I am trying to find out a better way to bind my json data to my html .
Json:
$scope.json = { 'one': { 'name': 'level1', 'two': { 'name': 'level2', 'three': { 'name': 'level3' } } } };
Html:
<div ng-controller="myController" >
<div ng-repeat="data in json"> -- (1)
<b>{{data.name}}</b>
<div ng-repeat="data1 in data">
<b>{{data1.name}}</b>
<div ng-repeat="data2 in data1 track by $index"><b>{{data2.name}}</b></div> -- (2)
</div>
</div>
</div>
Pointers : //marked in view
There is no array in my json data , so , is there a better way rather using ng-repeat (sort of traditional for) . Anything like with binding in knockout or templates (i'm not sure How) .
I see there are no duplicates in my json but still to compromise the error i have been using track by $index at the final inner div(if exclude final div i see no error) .
1: There is no array in my json data , so , is there a better way
rather using ng-repeat (sort of traditional for) . Anything like with
binding in knockout or templates (i'm not sure How) .
There is no way to use JSON object for ng-repeat but you can directly use JSON object using . operator for property.
Check below code
<div ng-controller="myController" >
<div>
<b>{{json.one.name}}</b>
<b>{{json.one.two.name}}</b>
<b>{{json.one.two.three.name}}</b>
</div>
</div>
2 : I see there are no duplicates in my json but still to compromise
the error i have been using track by $index at the final inner div(if
exclude final div i see no error).
The reason for error is because you are trying to get index of JSON object which doesn't has index.

ngRepeat doesn't $compile directives correctly

I have an array of items [Expression, Expression,....] and I add/remove Expression's from the array, but ngRepeat doesn't $compile the directive correctly.
What could be the reason for it?
One of the solutions is, that I have a separate array of Expressions, and I modify that one, and every time it changes I reset the "expressions" to [] and set the new array, but when doing this there is blinking of the UI elements (first digest to [] and then timeout(expressions = new array)).
// Main
scope.list = [Expressions.new(), Expressions.new()];
//constructor Expressions
function Expressions(){};
Expression.prototype = {
id: 'generated',
list: [
Expression.new(), Expression.new(),...
]
};
//constructor Expression
function Expression(){};
Expression.prototype = {
id: 'generated',
val: ''
};
<!-- Main Usage -->
<div ng-repeat="expressions in list track by $index" dir-expressions x-attrs="expressions"></div>
<!-- Expressions directive -->
<div class="Expressions_Content">
<ul ng-sortable="attrs.sortable">
<li ng-repeat="expression in attrs.items track by $index">
<div dir-expression x-attrs="expression"></div>
</li>
</ul>
</div>
<!-- Expression directive -->
<div>{{Value}}</div>
It is a complex situation, so I will just put some code snippets in the example.
As Sunil D pointed out, use track by expression.id instead of $index.

ng-repeat doesn't seem to be working

I am trying to pull all items from my array called 'collections'. When I input the call in my html I see only the complete code for the first item in the array on my page. I am trying to only pull in the 'edm.preview' which is the image of the item. I am using Angular Firebase and an api called Europeana. My app allows the user to search and pick which images they like and save them to that specific user.
here is the js:
$scope.users = fbutil.syncArray('users');
$scope.users.currentUser.collections = fbutil.syncArray('collections');
$scope.addSomething = function (something) {
var ref = fbutil.ref('users');
ref.child($rootScope.currentUser.uid).child('collections').push(something);
}
$scope.addSomething = function(item) {
if( newColItem ) {
// push a message to the end of the array
$scope.collections.$add(newColItem)
// display any errors
.catch(alert);
}
};
and the html:
<ul id="collections" ng-repeat="item in collections">
<li ng-repeat="item in collections">{{item.edmPreview}}</li>
</ul>
First, remove the outer ng-repeat. You want to only add the ng-repeat directive to the element which is being repeated, in this case <li>.
Second, from your AngularJS code, it looks like you want to loop over users.currentUser.collections and not just collections:
<ul id="collections">
<li ng-repeat="item in users.currentUser.collections">{{item.edmPreview}}</li>
</ul>
And third, you're defining the function $scope.addSomething twice in your JavaScript code. Right now, the second function definition (which, incidentally, should be changed to update $scope.users.currentUser.collections as well) will completely replace the first.

Resources