AngularJS: Conditional Chaining with JSON Filter - json

I am trying to conditionally display certain fields of JSON objects using filters. Currently it displays something like this:
JSON Ouput:[
{ tag: "Reading", checked: true },
{ tag: "Writing", checked: false },
{ tag: "Homework", checked: true},
{ tag: "Groupwork", checked: false }
];
Desired output:
Reading, Homework
Where I would only display those fields in which checked == true.
HTML/AngularJS:
<div class="item">
<pre ng-bind="tagList | json"></pre>
</div>
where tagList is the javascript object above.

You can use something like:
angular.module('myApp',[]).filter('tagsjson', function(){
return function(items){
var arrayToReturn = [];
for (var i=0; i<items.length; i++){
if (items[i].checked) {
arrayToReturn.push(items[i].tag);
}
}
return arrayToReturn.join();
};
});
You can then use your filter as:
<div class="item">
<pre ng-bind="tagList | tagsjson"></pre>
</div>
Here is a plunker demonstrating the above
PS: you can name your filter json but this will override the built in filter, as you have in your code, not sure if this is what you want.

Related

Dividing a sorted list

I have a list of movies and need to group them in both c# (or angular is also acceptable) and css very similary to the image provided here underneath. Any ideas on how to wire the html and c# and how to use the .groupBy() or something similar please ?
This is what I've got so far:
HTML (a list of all my movies in alphabetical order):
<div class="movs">
<movies-collection movies="::vm.sortedMovies" order-by="name"></movies-collection>
</div>
Typescript:
static id = "MoviesController";
static $inject = _.union(MainBaseController.$baseInject, [
"sortedMovies"
]);
static init = _.merge({
sortedMovies: ["allMovies", (movies: Array<Models.IGov>) => {
return _.sortBy(movies, "content.name");
}]
All my movies are already sorted alphabteically I just need to with the help of css structure them similarly to this image
I would create a filter that adds a "$first" property to the movie. If it is the first in a sorted list that starts with the character, then $first would be true. Bind to $first in your view when you show the character in uppercase.
The following demonstrates this idea:
var app = angular.module('app',[]);
app.controller('ctrl', function($scope) {
$scope.movies = [
{ title: 'The Godfather' },
{ title: 'Fargo' },
{ title: 'Sniper' },
{ title: 'Terminator'},
{ title: 'Click'},
{ title: 'Cake' },
{ title: 'Frozen' },
{ title: 'Casino Jack' },
{ title: 'Superman' },
{ title: 'The Matrix' }
];
});
app.filter('applyFirst', function() {
return function (movies) {
for(var i = 0; i < movies.length; ++i) {
if (i == 0)
movies[i].$first = true;
else {
if (movies[i].title.toLowerCase()[0] != movies[i-1].title.toLowerCase()[0]) {
movies[i].$first = true;
}
else {
movies[i].$first = false;
}
}
}
return movies;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.js"></script>
<div ng-app = "app" ng-controller="ctrl">
<div ng-repeat="movie in movies | orderBy:'title' | applyFirst">
<h1 ng-if="movie.$first">{{ movie.title[0] | uppercase }}</h1>
{{ movie.title }}
</div>
</div>
It's not possible in css, your code must split the array of movies into an array of letters, each with an array of movies.
You can use reduce for that:
var groupedMovies = movies.reduce((lettersArray, movie, idx, arr) => {
var firstLetter = movie[0].toUpperCase();
if (!lettersArray[firstLetter]) {
lettersArray[firstLetter] = [movie];
}
else {
lettersArray[firstLetter].push(movie);
}
return lettersArray;
}, []);
The result will look something like this:
[ T: [ 'The Avengers', 'Tower Quest', 'ThunderFist', 'Transformers' ],
U: [ 'Untamed Bengal Tiger', 'Untamed Giant Panda' ],
V: [ 'Victorious' ] ]
This way you can do a loop on the letters array, and in each do another loop for each movie.
The best practice for that would be to create a directive for a grouped movies, it will receive the letter and the inner array of movies in that letter.

How to display the returned ajax Json results in HTML (using typescript)

The client (typescript) gets different results from the server, all are in json format. Sometimes a simple json result, sometimes complex nested jsons.
I need to present the results in a (very) simple html table.
function run(): void {
var url = this.selectedKnockoutDropList();
$.ajax(url, "GET").done(data => {
console.log(data);
*** here I want to do something like :
- open/embedd results.html
- fill a table with the json results parsed somehow
});
I tried $('#...).html(data) with no success.
You need to transform the JSON into meaningful HTML. This can be done in typescript, javascript. It can be done with jQuery it can be done using javascript templates such a handlebars. It can be done with SPA frameworks like Angular.
Please post an a sample of the returned JSON and I can update with a TypeScript example not using any toolsets or libs.
JSON is an object. To output it to the document you need to first convert it to a string:
$.ajax(url, "GET").done(data => {
$('#...).html(JSON.stringify(data));
}
However, if you know what kind of data you are getting back and want to output just parts of it, you'll need to loop the JSON. For example, if you had a JSON object like:
[
{name: "Joe", age: 32},
{name: "Suzy", age 23},
{name: "Tom", age 28}
]
You could output the names like this:
$.ajax(url, "GET").done(data => {
data.forEach(function(person) {
$(ul).append('<li>' + person.name + '</li>');
});
}
Martin and Robert - thanks for the quick replies. I took your advises and came with the following generic solution (which can display html text returned from the server or nested json object in a table) :
HTML:
<!--HTML-->
<div data-bind="visible: isHtml, html: htmlView"></div>
<!--SIMPLE JSON-->
<div data-bind="visible: isJson">
<table>
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: $data"></th>
</tr>
</thead>
<tbody data-bind="foreach: rows">
<tr data-bind="foreach: $parent.columns">
<td data-bind="text: $parent[$data]"></td>
</tr>
</tbody>
</table>
</div>
TS:
function run(): void {
this.isHtml(false);
this.isJson(false);
$.ajax(url, "GET").done(data => {
var jsonObj = data;
if (typeof (data) === "string") {
this.htmlView(data);
this.isHtml(true);
return;
}
if (data instanceof Array === false) {
jsonObj = [data];
}
this.columns([]);
this.rows([]);
for (var i = 0; i < jsonObj.length; i++) {
var item = jsonObj[i];
var newItem = {};
for (var key in item) {
if (i === 0)
this.columns.push(key);
if (typeof item[key] !== "object") {
newItem[key] = item[key];
} else {
for (var deeperKey in item[key]) {
this.columns.push(deeperKey);
newItem[deeperKey] = item[key][deeperKey];
}
}
}
this.rows.push(newItem);
}
this.isJson(true);
});
I used another stackoverflow post (which I can't find right now) for the nested rows. Obviously flatting the sub-rows is not what I want but it can easily be changed.
It's my first typescript/html program :)
Thanks Again!

Angularjs filter - Compare multiple checkboxes boolean with JSON list, display union

In the view there are three checkboxes that change the states of the three values of $scope.colorChoice.
I would like to write a function that compares every true color to the corresponding color in the JSON list.
If a person has at least one color in its array that has been checked true,
the persons name should be displayed.
How can i write such a function?
So far I've come so far:
JSON list:
[
{
"name": "kevin",
"colors": ["red, green"]
},
{
"name": "hans",
"colors": ["green"]
},
{
"name": "jolene",
"colors": ["red, blue"]
},
{
"name": "peter",
"colors": ["blue"]
}
]
Checkboxes:
<label ng-repeat="(item,enabled) in colorChoice">
<input type="checkbox" ng-model="colorChoice[item]">
</label>
Controller:
$scope.colorChoice = {
red: false,
green: false,
blue: false
};
For example:
$scope.colorChoice = {
red: true,
green: false,
blue: true
};
...would display:
Kevin, Jolene, Peter
Thanks for your help!
Vin
One thing you might want to look into is the angular-checklist-model,
http://vitalets.github.io/checklist-model/
That won't solve your problem as I see you are already handling what it would handle for you. I find it very clean to use for a purpose like yours though.
With that colorChoice object you could do something like this whether you use angular-checklist-model or not though:
HTML
<ul>
<li ng-repeat='person in people | filter: colorFilter'>{{person.name}}</li>
</ul>
Controller Filter Function
$scope.colorFilter = function(person) {
for (var i = 0; i < person.colors.length; i++) {
var color = person.colors[i];
if ($scope.colorChoice[color] == true)
return true;
}
return false;
};
I like to use the angular filters like so with functions that return true or false. They can be extremely versatile for situations like this.
angular filter guide
Thanks Kyle - The checklist-model looks very interesting.
I've come up with the following solution now:
First a little helper function to filter out all activated checkboxes:
$scope.colorChoiceTrue = function () {
var result = [];
for (var key in $scope.colorChoice) {
if ($scope.colorChoice[key] === true) {
result.push(key);
};
};
return result;
}
Another helper function to search a string in an array:
$scope.searchStringInArray = function (str, strArray) {
for (var j = 0; j < strArray.length; j++) {
if (strArray[j].match(str)) return true;
}
return false;
}
Finally, this function returns every person who has at least one color matching the colorChoice:
$scope.peopleSelected = function () {
var result = [];
angular.forEach($scope.people, function (entry, key) {
if ($scope.searchStringInArray(entry.color, $scope.colorChoiceTrue())) {
result.push(entry.name);
};
});
return result;
};

ng-init json Object

I use angularjs (ng-init) and I want to assign value to variable as jsonObj.
I try this one but it doesn't work.
ng-init="percentObj = [{ "value":40,"color":"#F5A623" },{ "value":60,"color":"#F5A623" }];
and another question
I want to assign value like
percentObj = [{ "value": parseInt($scope.projectData[0].value),"color":"#F5A623" },{ "value": parseInt($scope.projectData[0].value),"color":"#F5A623" }]
How to fix this problem??
Thx
You can use window object for set your json :
<script type="text/javascript">
window.data= {awesome:1};
</script>
view :
<div ng-controller="myCntrl" ng-init="init('data')">
controller :
function myCntrl($scope) {
$scope.init = function (settings) {
settings = window[settings];
console.log(settings.awesome); //1
};
}
Escape your quotes...
ng-init="percentObj = [{ \"value\":40,\"color\":\"#F5A623\" },{ \"value\":60,\"color\":\"#F5A623\" }];"
Try this...
<body ng-controller="TestController">
<div ng-init="Init()">
{{percentObj || json }}
</div>
</body>
$scope.Init = function()
{
$scope.percentObj = [{ "value":40,"color":"#F5A623" },{ "value":60,"color":"#F5A623" }]
}
Just have a JSON encoded string in some element's attribute and then catch that with Angular.
HTML
<div data-config="{title:'this is my title'}" my-directive></div>
AngularJS:
app.directive('myDirective', function () {
return {
restrict: 'A',
link: function (scope, element) {
// apply config from element's data-config attribute
scope.config = element.data('config');
// print out the data in console
console.log(scope.config);
}
};
});
Can be done without jQuery too, then the .data('config') part changes.
for second one, Please check the code below
var obj = {};
$scope.percentObj = [];
obj.value = parseInt($scope.projectData[0].value);
obj.color = "#F5A623";
$scope.percentObj.push(obj);

Knockout.js binding to json object memebr prefixed with #

I have converted some XML to Json using JSON.Net and am then binding to a view using Knockout.js.
The problem I have is that my XML attributes are represented in json, prefixed with an #,which is seen an illegal character in Knockout.js.
My view model has the following:
self.titles = ko.computed(function () {
var str = self.searchForText().toLowerCase();
return jsonString.AutoPolicy.Policy.filter(function (el) {
return el['#id'].toLowerCase().indexOf(str) == 0;
});
}, self);
and my html:
<div id="searchResultsDiv" class="sectionDiv">
<div data-bind="foreach: titles">
<div data-bind="text: #id, click: $parent.isSelected, event : { dblclick: $parent.openFileDblClick }"></div>
</div>
</div>
How do I bind to the attribute? Is there an escape key, or an alternative way to return from the view model?
EDIT
I have modified my view model to add an element that knockout can bind to:
// bind a list to json data **NEEDS TO VE ALL TITLES**
self.titles = ko.computed(function () {
var str = self.searchForText().toLowerCase();
jsonString.AutoPolicy.Policy['#id']
return jsonString.AutoPolicy.Policy.filter(function (el) {
el.id = el['#id'];
return el['#id'].toLowerCase().indexOf(str) == 0;
});
}, self);
This gives the desired results but is there a better way?
Thanks
Try something like this:
<div data-bind="text: $data['#id']"></div>