AngularJs new line after special character when binding - javascript

I have an angularJS project where I requested data from the server and the returned JSON object with a list of countries name like this :
$scope.countries=[{
countriesName : 'USA, England, Germany, France'
}];
so when I bind the data to render it in view I use ng-repeat like this :
<tbody>
<tr ng-repeat="country in countries">
<td>{{country.countriesName }}</td>
</tr>
</tbody>
the current view :
Countries Name :
-----------------
USA, England, Germany,France
but I want in the view to split this names by special character which in this case `(,) and then write the next name in new line at the same
so the expected view something like this :
Countries Name :
-----------------
USA,
England,
Germany,
France
Note:
-That binding the countries name returns in one string line and I bind this names in in a table at once time
-I want one <td> with 4 different lines

You may generate different divs after splitting the countriesName by a space. Since divs have block display, the contents will automatically take up new lines.
I prefer this approach to not deal with sanitizing the generate HTML content (by using <br> tags), as it will require including ngSanitize module.
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.countries = [{
countriesName: 'USA, England, Germany, France'
}];
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<table>
<tbody>
<tr>
<td ng-repeat="country in countries">
<div ng-repeat="line in country.countriesName.split(' ')">
{{line}}
</div>
</td>
</tr>
</tbody>
</table>
</div>

Try this please:
<tbody>
<tr ng-repeat="country in countries">
<td ng-repeat="name in country.countriesName.split(',')">
{{ name }}
</td>
</tr>
</tbody>

Related

Html/Angular toggle table rows to show hidden a table

I am completely new to angular, I need to create a table. The data array is as-follows:-
data = [{rollno: 1,name: 'abc',subject: 'maths'},
{rollno: 4,name: 'xyz',subject: 'history'},
{rollno: 2,name: 'pqr',subject: 'history'}
];
I want to create a table with some summary rows based on this data and then when I click the expand button the sub-rows should appear beneath that summary-row indicating the actual data.
For example:-
Expand/Collapse | No of Students | Subject
click here 1 Maths
click here 2 History
When I toggle the expand/collapse button on the second row for example I want actual rows to appear like this beneath it:-
Expand/Collapse | No of Students | Subject
click here 1 Maths
click here 2 History
RollNo | StudentName
4 xyz
2 pqr
How Can I achieve this?
1) Grouping the data by subject
First you need to group the data by subject and then count the items in each group.
You can use the angular.filter module's groupBy filter to do this.
1a) Add a dependency on that module as follows:
var app = angular.module("yourModuleName", ["angular.filter"]);
1b) You can then use the groupBy filter in an ng-repeat directive on a <tbody> tag like this:
<tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
1c) You're now dealing with the data in the format below. This is an object of key/value pairs where "maths" and "history" are both keys, and the arrays are the values
{
"maths": [
{
"rollno": 1,
"name": "abc",
"subject": "maths",
}
],
"history": [
{
"rollno": 4,
"name": "xyz",
"subject": "history",
},
{
"rollno": 2,
"name": "pqr",
"subject": "history",
}
]
}
2) Displaying the grouped data and counting the items in each group
Use key and value to display the grouped data in a table as follows:
<table>
<thead>
<tr>
<th>Subject</th>
<th>Number of Students</th>
<th>Expand/Collapse</th>
</tr>
</thead>
<tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
<tr>
<td>{{ key }}</td>
<td>{{ value.length }}</td>
<td>
<button>
Expand/Collapse
</button>
</td>
</tr>
<tr>
<td colspan="3">
<table>
<thead>
<tr>
<th>Roll Number</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="student in value">
<td>{{ student.rollno }}</td>
<td>{{ student.name }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
Note the extra <tr> and nested table with another ng-repeat for displaying the student data. Currently all nested student data will display, the next step is to conditionally show/hide the nested tables based on which expand/collapse button was clicked.
3) Showing/Hiding the nested student data
3a) Add an ng-click directive on the button so that it passes in the key to an onExpandClicked function on your controller:
<button ng-click="onExpandClicked(key)">
Expand/Collapse
</button>
3b) Create the onExpandClicked function in your controller:
$scope.onExpandClicked = function(name){
$scope.expanded = ($scope.expanded !== name) ? name : "";
}
This sets a value on the $scope that can be used in the view to decide whether to show/hide a section of student data. The key is passed into the function as the name parameter and $scope.expanded will either be set to name or reset to "" depending on whether the passed in name is the same as the current $scope.expanded value or not.
3c) Finally, use the $scope.expanded variable in an ng-if directive on the second <tr> tag of <tbody> to show or hide the nested student data:
<table>
<thead>
<tr>
<!-- Omitted for brevity -->
</tr>
</thead>
<tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
<tr>
<!-- Omitted for brevity -->
</tr>
<tr ng-if="expanded === key">
<!--
Omitted for brevity
-->
</tr>
</tbody>
</table>
Demo
CodePen: How to show/hide grouped data created by the angular.filter module's groupBy filter
Design a table with html and iterate through your data object with ng-repeat loop to display the data.
ngRepeat
W3Schools has some basic examples on how to display tables with AngularJS
Angular Tables
First you should replace the actual table by a div structure, because it is not possible to mix two kinds of table like you are planning (when I get you right).
You could toggle every row with a ng-click with the corresponding expanded content like this (pseudo code, I hope the idea gets clear):
<div class="row-header">
<span>RollNo</span>
<span>StudentName</span>
</div>
<div class="row-content" ng-if="!row_4_expanded" ng-click="row_4_expanded = !row_4_expanded">
<span>4</span>
<span>xyz</span>
</div>
<div ng-if="row_4_expanded">
<div class="row-expanded-header">
<span>No of Students</span>
<span>Subject</span>
</div>
<div class="row-expanded-content">
<span>1</span>
<span>Math</span>
</div>
<div class="row-expanded-content">
<span>2</span>
<span>History</span>
</div>
</div>
<div class="row-content" ng-if="!row_2_expanded" ng-if="row_2_expanded" ng-click="row_2_expanded = !row_2_expanded">
<span>2</span>
<span>pqr</span>
</div>
<div ng-if="row_2_expanded">
<div class="row-expanded-header">
<span>No of Students</span>
<span>Subject</span>
</div>
<div class="row-expanded-content">
<span>1</span>
<span>Math</span>
</div>
<div class="row-expanded-content">
<span>2</span>
<span>History</span>
</div>
</div>
When you now click on a row, it toggle presens with the corresponding expanded one.
Here is a working example which resolves your problem.
var indexCtrl = ['$scope', function($scope){
$scope.num = 0;
$scope.test = [{rollno: 1,name: 'abc',subject: 'maths'},
{rollno: 4,name: 'xyz',subject: 'history'},
{rollno: 2,name: 'pqr',subject: 'history'}
];
$scope.changeShow = function(index){
$scope.num = index;
};
}];
<!DOCTYPE html>
<html ng-app>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-controller='indexCtrl'>
<table>
<tr>
<td>Expand/Collapse</td>
<td>No of Students</td>
<td>Subject</td>
</tr>
<tr ng-repeat='i in test' ng-class="num == $index ? red : none">{{}}
<td ng-click='changeShow($index)'>click here</td>
<td>{{$index +1}}</td>
<td >{{i.subject}}</td>
</tr>
</table>
<table>
<tr>
<td>RollNo</td>
<td>StudentName</td>
</tr>
<tr ng-repeat='i in test'>
<td ng-show='num == $index'>{{i.rollno}}</td>
<td ng-show='num == $index'>{{i.name}}</td>
</tr>
</table>
<style>
table tr td{
border: 1px solid black
}
</style>
</body>
</html>
Hope it helps you.

passing $scope objects to ng-if and ng-class ternary condition not working

**main.js:**
$scope.status = [
{name:'SQL', stat:"up"},
{name:'Web Server', stat:"down"},
{name:'Index', stat:"down"}
];
**index.html:**
<table>
<tr>
<td ng-repeat="x in status">
<div ng-if="{{x.name}}=='SQL'"> {{x.stat}} </div>
</td>
</tr>
</table>
<table>
<tr>
<td ng-repeat="x in status">
<div ng-if="{{x.name}}=='SQL'" ng-class="{{x.stat}}=='up'? 'squareGreen':'squareRed'"> {{x.name +" : "+x.stat}} </div>
</td>
</tr>
</table>
I am trying to pass status array to index.html to compare the 'name' to a string then apply class squaregreen or red depending upon comparison of 'stat' to 'up' or 'down'. The goal is to match the name of the server and apply green when up and red when down. I have 2 problems below. 1. parse error in syntax for ng-if 2. all servers are applied Squarered, though 1st server(sql)'s 'stat' is 'up'
Remove all the curly braces from your ng-if and ng-class expressions and it should work. E.G:
main.js:
$scope.status = [
{name:'SQL', stat:"up"},
{name:'Web Server', stat:"down"},
{name:'Index', stat:"down"}
];
**index.html:**
<table>
<tr>
<td ng-repeat="x in status">
<div ng-if="x.name=='SQL'"> {{x.stat}} </div>
</td>
</tr>
</table>
<table>
<tr>
<td ng-repeat="x in status">
<div ng-if="x.name=='SQL'" ng-class="x.stat=='up'? 'squareGreen':'squareRed'"> {{x.name +" : "+x.stat}} </div>
</td>
</tr>
</table>
Curly braces are not necessary here because ng-if and ng-class bindings are evaluated as scope expressions already. Use curly braces when a directive does not do this by default (e.g. with '#' bindings). AngularJS docs on scope binding
Take out your curly braces. ng-if="x.name === 'SQL'"
You don't need to use the extrapolation {{}} operator within ng-if and you need to use the {} within your ng-class
<div ng-if="x.name == 'SQL'" ng-class="{x.stat=='up'? 'squareGreen':'squareRed'}"> {{x.name +" : "+x.stat}} </div>

Splitting a string in JSON and using them in two separate tds with angular

So I'm calling a JSON string, and I want to split it in two at the ":" and use the two values to show in two separate td tags.
function testCtrl($scope) {
$scope.response = {"name":["The name field is required."],"param":["Hobby: Coding", "Country: USA"]};}
to visualize a little more at what I'm trying to do http://jsfiddle.net/8mnxLzc1/5/
You could try this:
<table>
<tr ng-repeat="resp in response.param">
<td ng-repeat="val in resp.split(':')">{{ val }}</td>
</tr>
</table>
Fiddle
This is a entirely angular solution, no need to call the function split in the ng-repeat.
https://jsfiddle.net/kLjzh565/
<table>
<tr ng-repeat="resp in response.param track by $index">
<td ng-repeat="i in [$index]">
{{response.param[i]}}
</td>
</tr>
</table>

AngularJS: modify value within ng-repeat

I have a simple table in Angular:
<table>
<tr ng-repeat="row in $data">
<td>{{row.name}}</td>
<td>{{row.surname}}</td>
</tr>
</table>
that would render something like this:
<table>
<tr>
<td>Johnathan</td>
<td>Smith</td>
</tr>
<tr>
<td>Jane</td>
<td>Doe</td>
</tr>
</table>
but I have a dynamic search function that reloads the table and I need to highlight the search string in results like so (the search word is "John"):
<table>
<tr>
<td><span class="red">John</span>athan</td>
<td>Smith</td>
</tr>
</table>
now I hoped that something like this would work:
<table>
<tr ng-repeat="row in $data">
<td>{{myFunction(row.name)}}</td>
<td>{{row.surname}}</td>
</tr>
</table>
but it doesn't. Any way to make this work?
UPDATE: Solved, solution proposed by #loan works in this case.
As you'll see in the example below, you can do something similar to this.
Example
In your existing loop you can add the custom filter as follows:
<body ng-controller="TestController">
<h1>Hello Plunker!</h1>
<input type="text" ng-model="query" />
<ul>
<li ng-repeat="item in data | filter:query">
<!-- use the custom filter to highlight your queried data -->
<span ng-bind-html="item.name | highlight:query"></span>
</li>
</ul>
</body>
In your JavaScript file you can create the custom filter:
(function() {
'use strict';
angular.module("app", []);
//to produce trusted html you should inject the $sce service
angular.module("app").filter('highlight', ['$sce', function($sce) {
function escapeRegexp(queryToEscape) {
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
}
return function(matchItem, query) {
return $sce.trustAsHtml(query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem);
};
}]);
angular.module("app")
.controller('TestController', ['$scope',
function($scope) {
$scope.query = ""; //your scope variable that holds the query
//the dummy data source
$scope.data = [{
name: "foo"
},{
name: "bar"
},
{
name: "foo bar"
}];
}
]);
})();
if you want you can replace the html in the filter with your values:
<strong>$&</strong>
to
<span class="red">$&</span>
use ng-class, so the html for your td becomes
<td ng-class = "{red: row.name == searchStr}">{{row.name}}</td>
There are other formats for ng-class and my html may be dodgy I use haml mostly but check the docs on ng-class
You can use angular-ui's highlight module. You can simply use it like this:
DEMO
HTML
<div>
<input type="text" ng-model="searchText" placeholder="Enter search text" />
</div>
<input type="checkbox" ng-model="caseSensitive" /> Case Sensitive?
<table>
<tbody>
<tr ng-repeat="row in $data">
<td ng-bind-html="row.name | highlight:searchText:caseSensitive"></td>
<td>{{row.surname}}</td>
</tr>
</tbody>
</table>
You can download it via bower, instructions are provided in their github page.
Note: Add angular's ngSanitize to avoid an $sce unsafe error.

Angular JS object as ng-model attribute name

I'm creating a dynamic angular js application wherein I want to use a textbox as a searchtext for the filter of a table. Here's a preview on what I am doing:
As of now, my code looks like this
<table>
<thead>
<tr class="filterrow">
<td data-ng-repeat="col in items.Properties">
<input id="{{col.DatabaseColumnName}}" type="text"
data-ng-model="search_{{col.DatabaseColumnName}}"/>
<!-- Above Here I want to dynamically assign the ng-model based on Databasecolumnname property-->
</td>
</tr>
<tr>
<th data-ng-repeat="col in items.Properties">{{col.ColumnTitle}}</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="content in items2.Contents | filter: search_{{col.DatabaseColumnName}}: search_{{col.DatabaseColumnName}}">
<td data-ng-repeat="col in items.Properties">
{{content[col.Databasecolumnname ]}}
</td>
</tr>
</tbody>
</table>
I already tried the approach of using $compile but I wasn't able to implement it. Any ideas in an approach? Thanks!
EDIT: Plnkr - plnkr.co/edit/5LaRYE?p=preview
You can do this by setting a base object for your ng-Models. So in your controller you will have:-
$scope.search = {};
and in your view do:-
<input ng-attr-id="{{col.DatabaseColumnName}}" type="text"
data-ng-model="search[col.DatabaseColumnName]"/>
With this your dynamic ng-model will be assigned to the search base object, ex:- if col.DatabaseColumnName is col1 then ngModel would be $scope.search.col1

Categories

Resources