How can I apply ng-style dynamically if ng-class is true? - angularjs

.test{color:red;background:blue;}
.test.selected {
position:relative; left: 100px; padding:10px; background:green;
}
<div ng-style="myStyle" ng-class="{select: x.selected}" ng-click="select(x)" ng-repeat="x in myData" class="test"></div>
$scope.select = function (text) {
text.selected = true;
};
$scope.myStyle = {
'color':'white',
'font-weight':'bold'
}
When the div element has className "selected" by using condition true, how can I add 'myStyle' in ng-style as well. How to apply inline ng-style dynamically if ng-class condition is true? Here below I am able to see in debugger in inline with classNames added. Now I have the condition true and I can see the classname "selected" to it(class="test ng-scope selected"), All I want is an inline ng-style="myStyle" to be added when its true.
<div ng-class="{select: x.selected}" ng-click="select(x)" class="test ng-scope selected" ng-repeat="x in myData">

Try like to this.
<div ng-style="x.selected && {'color':'white','font-weight':'bold'}"
ng-click="select(x)" ng-repeat="x in myData" ></div>
Demo
var app = angular.module('anApp', ['angular.filter']);
app.controller('aCtrl', function($scope) {
$scope.data = [
{
"id": 100,
"value": "2452"
},
{
"id": 100,
"value": "2458"
},
{
"id": 1,
"value": "2457"
},
{
"id": 1,
"value": "2459"
},
{
"id": 4,
"value": "2460"
},
{
"id": 5,
"value": "3458"
}
];
$scope.select = function(x){
x.selected = !x.selected;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>
<div ng-app="anApp" ng-controller="aCtrl">
<div ng-style="x.selected && {'color':'red','font-weight':'bold'}"
ng-click="select(x)" ng-repeat="x in data" >
{{x.value}}
</div>
</div>

Dont use ng-style for selected item, you can do this with ng-class(Recommended)
Style
.selected {
'color':'white',
'font-weight':'bold'
}
HTML
<div ng-class="{'selected': x.selected}" ng-click="select(x)" ng-repeat="x in myData" ></div>
Controller
$scope.select = function(x){
x.selected = !x.selected;
}

Related

best practice and performance in angularJS ng-if with class and icon

2 options:
what is better for performance and watchers using, now I am using the first option and I would like to improve performance
the object today looks like:
message = {
message : X,
}
and I would like to do somthing like :
obj = {
text : text,
icon: "src.png"
status: X,
class : "className",
color: "color_code_like_#ffff"
}
1 :
<div ng-if="message.message == 0" class="classA" style="">
<span class="same"><img class="sameClass" ng-src="a.gif"></span>
<span class="status-text a_with_animation" style="color:red;">textA</span>
</div>
<div ng-if="message.message == 1" class="classB" style="">
<span class="same"><img class="sameClass" ng-src="b.png"></span>
<span class="status-text" style="color:blue;">textB</span>
</div>1
<div ng-if="message.message == 2" class="classC" style="">
<span class="same"><img class="sameClass" ng-src="c.png"></span>
<span class="status-text" style="color:black;">TextC</span>
</div>
option 2
<div class="{{obj.class}}" style="">
<span class="same"><img class="sameClass" ng-src="{{obj.class}}"></span>
<span class="status-text {{obj.animation}" style="color:red;">
{{obj.text}}</span>
</div>
also all the data here is two way binding
Not really pretty but I made an example of how you could populate your data with ng-include template. Here is a demo:
<!DOCTYPE html>
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-controller="myCtrl">
<select ng-model="message" ng-change="change()" ng-options="x.message for x in messages">
</select>
<br>
ngInclude: <div ng-include="'abc.html'"></div>
Directive: <div temp-directive></div>
<!-- A separate file for the template -->
<script type="text/ng-template" id="abc.html">
<div class="{{obj.class}}" style="">
<span class="same"><img class="sameClass" ng-src="{{obj.icon}}"></span>
<span class="status-text {{obj.animation}}" ng-style="obj.style">
{{obj.text}}</span>
</div>
</script>
</div>
<script>
var app = angular.module('myApp', []);
app.directive("tempDirective", function() {
return {
template : "<div class='{{obj.class}}' style=''><span class='same'><img class='sameClass' ng-src='{{obj.icon}}'></span><span class='status-text {{obj.animation}}' ng-style='obj.style'> {{obj.text}}</span></div>"
};
});
app.controller('myCtrl', function($scope) {
$scope.messages = [{
"message": 0
}, {
"message": 1
}, {
"message": 2
}];
$scope.message = $scope.messages[0]; // initialise
$scope.objects = [{
"text": "Message - 0",
"icon": "a.gif",
"animation": "a_with_animation",
"class": "classA",
"style": {
"color": "#00aaaa"
}
}, {
"text": "Message - 1",
"icon": "b.png",
"animation": "",
"class": "classB",
"style": {
"color": "#aa00aa"
}
}, {
"text": "Message - 2",
"icon": "c.png",
"animation": "",
"class": "classC",
"style": {
"color": "#aaaa00"
}
}];
$scope.obj = $scope.objects[0]; // initialise
$scope.change = function() { // changing the template data
$scope.obj = $scope.objects[$scope.message.message];
}
});
</script>
</body>
</html>
[Note]: it is best to replace ng-include with a component / directive with their template (not templateUrl) for performance improvement, since it is asynchronous and takes time to load the HTML

Angular js - Multiple input per row edit & save

<div ng-controller="MyController">
<table border="1">
<tr data-ng-repeat="item in items">
<td data-ng-repeat="textValue in item.value">
<input type="text" data-ng-model="textValue" data-ng-readonly="isReadonly" />
</td>
</tr>
</table>
<input type="button" value="Edit" data-ng-click="enableEdit();" />
</div>
Will have multiple rows with multiple input type text for each row. Initially onload input type are set to readonly. Once user press the edit button all of the input box will become editable. User can change the text box values & save the updated values by clicking on save button.
var MyModule = angular.module('MyModule', []);
MyModule.controller("MyController", function($scope) {
$scope.isReadonly = true;
$scope.items = [{
"id": 1,
"value": {
"value1": 10,
"value2": 20,
"value3": 30,
"value4": 40
}
}, {
"id": 2,
"value": {
"value1": 50,
"value2": 60,
"value3": 70,
"value4": 80
}
}];
$scope.enableEdit = function() {
$scope.isReadonly = false;
}
});
Follow the below plnkr url
http://plnkr.co/edit/g0bpUg2AVjNhWAXG8PXc?p=preview
You should be using ng-if to toggle between the controls as below
<tr data-ng-repeat="item in items">
<td data-ng-repeat="textValue in item.value">
<label class="form-control" ng-if="isReadonly">{{textValue}} </label>
<input type="text" ng-if="!isReadonly" data-ng-model="textValue" />
</td>
</tr>
Controller Method
$scope.enableEdit = function() {
$scope.isReadonly = false;
}
$scope.saveValues=function(){
$scope.isReadonly = true;
}
LIVE DEMO(UPDATED PLUNK)
I assume the problem you are facing is related to changes not getting reflected back to the model.
The assumption was made because you haven't told us your problem in the first place.
Note: I've also added the saveValues() function for completeness.
The problem is due to how ngRepeat directive works and how you have used it. ng-repeat creates a child scope for each textValue and in these child scopes, ng-repeat does not create a 2-way binding for the textValue value. And so your model was never updated.
There are two different ways to solve this:
P.S: Example#2 is just for the demonstration of object technique and should be avoided for your use-case as it would further complicate the data structure of items.
Example#1) Using (key, value) like:
var MyModule = angular.module('MyModule', []);
MyModule.controller("MyController", function($scope) {
$scope.isReadonly = true;
$scope.items = [{
"id": 1,
"value": {
"value1": 10,
"value2": 20,
"value3": 30,
"value4": 40
}
}, {
"id": 2,
"value": {
"value1": 50,
"value2": 60,
"value3": 70,
"value4": 80
}
}];
$scope.enableEdit = function() {
$scope.isReadonly = false;
}
$scope.saveValues = function() {
$scope.isReadonly = true;
console.log($scope.items)
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html ng-app="MyModule">
<div ng-controller="MyController">
<table border="1">
<tr data-ng-repeat="item in items">
<td data-ng-repeat="(key, textValue) in item.value">
<input type="text" data-ng-model="item.value[key]" data-ng-readonly="isReadonly" />
</td>
</tr>
</table>
<input type="button" value="Edit" data-ng-click="enableEdit();" />
<input type="button" value="Save" data-ng-click="saveValues();" />
</div>
Example#2) Using objects like:
var MyModule = angular.module('MyModule', []);
MyModule.controller("MyController", function($scope) {
$scope.isReadonly = true;
$scope.items = [{
"id": 1,
"value": {
"value1": {
"value": 10
},
"value2": {
"value": 20
},
"value3": {
"value": 30
},
"value4": {
"value": 40
}
}
}, {
"id": 2,
"value": {
"value1": {
"value": 50
},
"value2": {
"value": 60
},
"value3": {
"value": 70
},
"value4": {
"value": 80
}
}
}];
$scope.enableEdit = function() {
$scope.isReadonly = false;
}
$scope.saveValues = function() {
$scope.isReadonly = true;
console.log($scope.items)
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html ng-app="MyModule">
<div ng-controller="MyController">
<table border="1">
<tr data-ng-repeat="item in items">
<td data-ng-repeat="textValue in item.value">
<input type="text" data-ng-model="textValue.value" data-ng-readonly="isReadonly" />
</td>
</tr>
</table>
<input type="button" value="Edit" data-ng-click="enableEdit();" />
<input type="button" value="Save" data-ng-click="saveValues();" />
</div>

ng-repeat in other ng-repeat is not working

{
"data": {
"name": "NAME",
"tests": [
{
"testname": "abc",
"relatedResource": [
{
"accessType": "fttb",
},
{
"accessType": "fttn",
}
]
},
{
"testname": "xyz",
"relatedResource": [
{
"accessType": "fttp",
},
{
"accessType": "fttp",
}
]
}
]
}
}
Controller
$scope.data=response.data.tests;
<div ng-repeat="l in data">
<div ng-repeat="i in l.relatedResource">
{{i.accessType}}
</div>
</div>
try this, you need multiple ng-repeat to access relatedResource
here I printed the output
<div ng-controller="MyCtrl">
<div ng-repeat="(key,val) in data">
{{val.name}}
<div ng-repeat="test in val.tests">
- {{test.testname}}
<div ng-repeat="resource in test.relatedResource">
- -{{resource.accessType}}
</div>
</div>
</div>
</div>
Try this snippet
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.data = {
"data": {
"name": "NAME",
"tests": [
{
"testname": "abc",
"relatedResource": [
{
"accessType": "fttb",
},
{
"accessType": "fttn",
}
]
},
{
"testname": "xyz",
"relatedResource": [
{
"accessType": "fttp",
},
{
"accessType": "fttp",
}
]
}
]
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="obj in data">
<span ng-repeat="val in obj.tests">
{{val.testname}}
<span ng-repeat="v in val.relatedResource">
{{v.accessType}}
</span>
<br/>
</span>
</div>
</div>
There is actually not much information about the question.
If you receive the json-data from a remote server, you should always check and convert it to a real json-object.
You can simply use
$scope.data = response.data.tests;
$scope.getData = function()
{
return angular.toJson($scope.data);
}
or you can test it with:
{{data | json}}

AngularJS : `Load more` button in each group of ng-repeat with many groups titles

I want to add load more button to the bottom of each group like the image here, and after clicking the button it shows rest of parts of the relevant group
where a,g are groups titles those have group property
In the snippet bellow, the code return only one load more button, and with no consideration of the group property.
var myApp = angular.module('myApp',[]);
myApp.controller('main', ['$scope', function($scope) {
$scope.test = "test";
$scope.filteredModules = [
{
"name":"a",
"group":"a"
},
{
"name":"b",
},
{
"name":"c",
},
{
"name":"c",
},
{
"name":"e",
},
{
"name":"f",
},
{
"name":"g",
"group":"g"
}
,{
"name":"h",
},
{
"name":"i",
},
{
"name":"j",
},
{
"name":"k",
}
,
{
"name":"l",
}
];
$scope.limit = 4;
$scope.loadMore = function() {
var increamented = $scope.limit + 4;
$scope.limit = increamented > $scope.filteredModules.length ? $scope.filteredModules.length : increamented;
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="main">
<div ng-repeat="node in filteredModules | limitTo:limit track by $index">
<div ng-if="!node.group">{{node.name}}</div>
<div ng-if="node.group" style="background-color:red">{{node.name}} </div>
</div>
<button ng-click="loadMore()">Load more</button>
</div>
</div>
Please try this snippet
var myApp = angular.module('myApp',[]);
myApp.controller('main', ['$scope', function($scope) {
$scope.filteredModules = {
"groups":
[
{
"title": "Alfreds Futterkiste",
"childs": ["child-1", "child-2", "child-3", "child-4", "child-5", "child-6","child-7", "child-8", "child-9"],
"limit": "3"
},
{
"title": "Ana Trujillo Emparedados y helados",
"childs": ["child-1", "child-2", "child-3", "child-4", "child-5", "child-6"],
"limit": "4"
},
{
"title": "Antonio Moreno Taquería",
"childs": ["child-1", "child-2", "child-3", "child-4", "child-5", "child-6"],
"limit": "3"
}
]
};
$scope.loadMore = function(index) {
$scope.filteredModules.groups[index].limit = parseInt($scope.filteredModules.groups[index].limit) + 3;
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="main">
<div ng-repeat="node in filteredModules.groups track by $index">
<div ng-if="node.title" style="background-color:red">{{node.title}}
</div>
<div ng-repeat="child in node.childs | limitTo: node.limit">
{{child}}
</div>
<br/>
<button ng-click="loadMore($index)" ng-hide="node.limit >= node.childs.length">Load more</button>
<br/><br/>
</div>
</div>
</div>

angularjs ng-repeat with dynamic json/object

I am looking a solution for dynamic data structure(inconsistent like different property name and property length) with ng-repeat. sample code are below.
$scope.data = [{
"table":[{
"employee":"name1",
"value1":"10",
"value2":"20"
},
{
"employee":"name2",
"value1":"15",
"value2":"30"
}]
},
{
"table":[{
"company":"name1",
"compnayValue":"12"
},
{
"company":"name2",
"compnayValue":"12"
}]
}]
<ul>
<li ng-repeat="item in data">
<table>
<tr ng-repeat="row in item.table">
<td>{{??}}</td>
<td>{{??}}</td>
</tr>
</table>
</li>
</ul>
You could enumerate all properties and display their values by another ng-repeat on td:
<li ng-repeat="item in data">
<table>
<tr ng-repeat="row in item.table">
<td ng-repeat="(key, value) in row">
{{row[key]}}
</td>
</tr>
</table>
</li>
but that would break the tabular format of data since some rows would have more tds. To prevent that you could first find out the set of all keys on all rows, do a th repeat with those first and then display them on the corresponding td below, e.g.:
<th ng-repeat="propertyName in allPossiblePropertyNames">
{{propertyName}}
</th>
and
<td ng-repeat="propertyName in allPossiblePropertyNames">
{{row[propertyName ]}}
</td>
Use <tbody> to represent an object inside table array and (key,value) syntax mentioned in iterating over object properties section to iterate over it's properties like:
angular.module('test', []).controller('testCtrl', function($scope) {
$scope.data = [{
"table": [{
"employee": "name1",
"value1": "10",
"value2": "20"
}, {
"employee": "name2",
"value1": "15",
"value2": "30"
}]
}, {
"table": [{
"company": "name1",
"compnayValue": "12"
}, {
"company": "name2",
"compnayValue": "12"
}]
}]
});
ul {
padding: 0;
}
ul li {
list-style-type: none;
margin-bottom: 10px;
}
table {
width: 100%;
table-layout: fixed;
background: #ebebeb;
}
tbody:nth-child(odd) tr {
color: #fff;
background: dodgerblue;
}
tbody:nth-child(even) tr {
color: #fff;
background: hotpink;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="testCtrl">
<ul>
<li ng-repeat="item in data">
<table>
<tbody ng-repeat="row in item.table">
<tr ng-repeat="(key, value) in row">
<td>
{{key}}
</td>
<td>
{{value}}
</td>
</tr>
</tbody>
</table>
</li>
</ul>
</div>
Check this plunker, you can define template depends on your data :
https://plnkr.co/edit/fVGhKZy5gnBzuPwspy5s?p=preview
Use angular filter :
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.data = [{
"table":[{
"employee":"name1",
"value1":"10",
"value2":"20"
},
{
"employee":"name2",
"value1":"15",
"value2":"30"
}]
},
{
"table":[{
"company":"name1",
"compnayValue":"12"
},
{
"company":"name2",
"compnayValue":"12"
}]
}]
})
.filter('isCompnay', function() {
return function(input) {
console.log(input.employee === undefined)
return input.company ? input : undefined;
};
})
.filter('isEmployee', function() {
return function(input) {
console.log(input.employee === undefined)
return input.employee ? input : undefined;
};
});

Resources