how to check that array inside an array has any value (angularjs) - angularjs

There is an array contentMetaDataList inside another array (content) which contents few field like title, name, etc. so how i can hide heading (smart tags: written inside p tag) when there is no title to display.
Smart Tags :
{{relatedcontent.title}}

You can use ng-show in order to show/hide by condition,
and to check if all the objects in your array includes the title field, you can use Array.every().
If you comment or remove one of those titles in the array, the wrapper <div> which show the titles won't be visible, but stays in the DOM tree. (removing from the DOM tree can be done by ng-if)
var app = angular.module('myApp', []);
app.controller('MainCtrl', ['$scope','$http', function($scope, $http){
$scope.a = 'sdf';
$scope.contentMetaDataList = [
{
title:"legislation_title",
fieldValue:"refund of tax to certain persons",
id:94346
},
{
title:"Enterprise_title",
fieldValue:"refund of tax to certain persons",
id:94346
},
{
title:"Related_title",
fieldValue:"refund of tax to certain persons",
id:94346
}];
$scope.checkTitle = function() {
return $scope.contentMetaDataList.every(item => item.title);
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MainCtrl">
<div>
<div ng-show="checkTitle()">
<p>Smart Tags : </p>
<div ng-repeat="relatedcontent in contentMetaDataList">
<div>
{{relatedcontent.title}}
</div>
</div>
</div>
</div>
</div>
</div>
for more info:
ng-show
Array.every()
ng-if

I would say add a <span> or some tag with a ngIf. *ngIf="relatedcontent.title !== undefined"

Related

Allow only one collapse div in ng-repeat

I have some data in the ng repeat, and inside that I have some data under each divs which is collapsed.
No when I click on the main div, I want only one div to collapse in at a time.
Eg: if I click abc, asdasd should be displayed.. Then if I click abc1, asdasd1 should be displayed but NOT asdasd
<script>
angular.module('myApp', [])
.controller("Ctrl_List", ["$scope", function(s) {
s.people = [
{name:"Sten", age:"49"}
,{name:"John", age:"39"}
,{name:"Hanne", age:"37"}
,{name:"Jens", age:"37"}
,{name:"Brian", age:"24"}
,{name:"Johnny", age:"24"}
,{name:"Peter", age:"49"}
]
s.obj = [
{
"name":'abc',
"text":'asdasd'
},
{
"name":'abc1',
"text":'asdasd1'
}
]
}])
html:
<body ng-app="myApp" ng-controller="Ctrl_List">
<div ng-repeat="ob in obj">
<button class="btn" data-toggle="collapse" href="#abc-{{ob.name}}"> {{ob.name}}</button>
<div id="abc-{{ob.name}}" class="collapse">{{ob.text}}</div>
</div>
</body>
data-parent is not working for me, or may be I am not using it properly.
Please Check the Fiddle here
Using a pure Angular approach rather than using JQuery for this.
Add a new property show to the each object and use ng-if to show/hide its corresponding text using a method in controller.
<div ng-repeat="ob in obj">
<button class="btn" ng-click=" showThis(ob)"> {{ob.name}}</button>
<div ng-if="ob.show">{{ob.text}}</div>
</div>
controller method
s.showThis = function(obj) {
//Hides all
angular.forEach(s.obj, function(ob) {
if(ob.name != obj.name) {
ob.show = false;
}
});
//Toggles current object show/hide
obj.show = !obj.show;
}
Working Fiddle

angularjs to output html clickable element instead of html as a string

I am using a filter to convert any URL or email id from a piece of content. but its getting rendered as a string not as a clickable HTML element.
Filter JS
angular.module('myApp.filters', []).filter('parseUrl', function() {
var urls = /(\b(https?|ftp):\/\/[A-Z0-9+&##\/%?=~_|!:,.;-]*[-A-Z0-9+&##\/%=~_|])/gim
var emails = /(\w+#[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim
return function(text) {
if (text.match(urls)) {
text = text.replace(urls, "$1")
}
if (text.match(emails)) {
text = text.replace(emails, "$1")
}
return text
}
});
this above code output me with a plane text and not clickable HTML elements.
Fiddle
I have updated JS Fidle
HTML:
Added
ng-bind-html
<div ng-app="miniapp">
<div ng-controller="Ctrl">
<h1 ng-bind-html="test | parseUrl">{{test}}</h1>
</div>
</div>
Documentation ngBindHtml
Your filter should make use of the Strict Contextual Escaping $sce to return trusted HTML
angular.module('myApp.filters', []).filter('parseUrl', function ($sce) {
var urls = /(\b(https?|ftp):\/\/[A-Z0-9+&##\/%?=~_|!:,.;-]*[-A-Z0-9+&##\/%=~_|])/gim
var emails = /(\w+#[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim
return function (text) {
if (text.match(urls)) {
text = text.replace(urls, "<a ng-href=\"$1\" target=\"_blank\">$1</a>");
}
if (text.match(emails)) {
text = text.replace(emails, "<a ng-href=\"mailto:$1\">$1</a>");
}
return $sce.trustAsHtml(text);
}
});
Update
It seems your are using an older version of Angular (version 1.0.2) which doesn't have the Strict Contextual Escaping $sce. That explains your usage of ngSanitize module.
Your filter code is correct, but you should bind your text differently using the ng-bind-html.
<div ng-app="miniapp">
<div ng-controller="Ctrl">
<h1 ng-bind-html="test | parseUrl"></h1>
</div>
</div>
JsFiddle : http://jsfiddle.net/fb4meygo/1/
With the help of linky filter we can detect links from text and show them differently. Linky takes text and produces HTML by wrapping all URLs into anchor tags. It supports email address, http, https, and mailto.
HTML:
<div ng-app="myApp" ng-controller="myController">
<div>
<p ng-bind-html="myText | linky :'_blank'"></p>
<textarea ng-model="myText" style="width: 420px; height: 120px"></textarea>
</div>
</div>
Controller:
var myApp = angular.module('myApp', ['ngSanitize'])
.controller('myController', ['$scope', function ($scope) {
$scope.myText = "Some default text is here http:/tothenew.com/";
}]);

From the include, how to show and hide the content according to the requirement?

I have a template in include. i am using that in 2 seperate instance in same page. how to i conditionally show the information within it?
code :
var myApp = angular.module("myApp", []);
myApp.controller("main", function($scope) {
$scope.firstTitle = true;
$scope.secondTitle = true;
});
html :
<div ng-controller="main">
<div class="show-first">
Your first info is :
<ng-include src="'info.html'"></ng-include>
//only need to show first tittle
</div>
<div class="show-second">
Your second info is:
<ng-include src="'info.html'"></ng-include>
//only need to show second tittle
</div>
</div>
<script type="text/ng-template" id="info.html">
<div>
<h1 ng-if="firstTitle">Info to show in first </h1>
<h1 ng-if="secondTitle">Infor to show in second </h1>
</div>
</script>
Live
If you want to show / hide segments of components based on a certain value/condition. You can follow this approach as well.
<div ng-show="isSectionShown()">
<h3>First Section Title</h3>
<div> Section Contents </div>
</div>
<div ng-show="isSectionShown()">
<h3>Second Section Title</h3>
<div> Section Contents </div>
</div>
angular.module('myApp', [])
.controller('MyController', function($scope) {
$scope.selectedSection = 'First';
$scope.isSectionShown = function() {
// This is for demonstration only, you can come with your implementation here to allow multiple checkings
return angular.equals($scope.selectedSection, 'First');
}
});
With similar conditional segments, you can use, ng-show, ng-hide, ng-if like statements.
Use two controllers separately to control the display of the template: Plunker.
.controller("oneCtrl", function($scope) {
$scope.firstTitle = true;
$scope.secondTitle = false;
}).controller("twoCtrl", function($scope) {
$scope.firstTitle = false;
$scope.secondTitle = true;
})
To fix this, you separate your templates.
<script type="text/ng-template id="info1.html">
<div>
<h1 ng-if="firstTitle">Info to show in first </h1>
</div>
</script>
<script type="text/ng-template id="info2.html">
<div>
<h1 ng-if="secondTitle">Info to show in second </h1>
</div>
</script>
The only other option is to access it form different controllers so you can turn one off and the other on. Separating the templates is the most versatile option IMO.

Use an Angular directive to generate html from an array

I'm trying to use an Angular directive to create a form where the user can specify the number of children and, for each child, an edit box appears allowing the childs date of birth to be entered.
Here's my HTML:
<div ng-app>
<div ng-controller="KidCtrl">
<form>
How many children:<input ng-model="numChildren" ng-change="onChange()"/><br/>
<ul>
<li ng-repeat="child in children">
<child-dob></child-dob>
</li>
</ul>
</form>
</div>
</div>
Here's the JS:
var app=angular.module('myApp', []);
function KidCtrl($scope) {
$scope.numChildren = 2
$scope.children = [{dob: "1/1/90"}, {dob: "1/1/95"}];
$scope.onChange = function () {
$scope.children.length = $scope.numChildren;
}
}
app.directive('childDob', function() {
return {
restrict: 'E',
template: 'Child {{$index+1}} - date of birth: <input ng-model="child.dob" required/>'
};
});
And here's a jsFiddle
The problem is that it's just not working.
If I enter 1 in the numChildren field then it shows 1 bullet point for the list element but it doesn't show any of the HTML.
If I enter 2 in the numChildren field then it doesn't show any list elements.
Can anyone explain what I'm doing wrong?
Many thanks ...
Your main issue is that the directive childDOB is never rendered. Even though your controller works because 1.2.x version of angular has global controller discover on. It will look for any public constructors in the global scope to match the controller name in the ng-controller directive. It does not happen for directive. So the absence of ng-app="appname" there is no way the directive gets rendered. So add the appname ng-app="myApp" and see it working. It is also a good practice not to pollute global scope and register controller properly with controller() constructor. (Global look up has anyways been deprecated as of 1.3.x and can only be turned off at global level.)
You would also need to add track by in ng-repeat due to the repeater that can occur due to increasing the length of the array based on textbox value. It can result in multiple array values to be undefined resulting in duplicate. SO:-
ng-repeat="child in children track by $index"
Fiddle
Html
<div ng-app="myApp">
<div ng-controller="KidCtrl">
<form>How many children:
<input ng-model="numChildren" ng-change="onChange()" />
<br/>
<ul>
<li ng-repeat="child in children track by $index">{{$index}}
<child-dob></child-dob>
</li>
</ul>
</form>
</div>
</div>
Script
(function () {
var app = angular.module('myApp', []);
app.controller('KidCtrl', KidCtrl);
KidCtrl.$inject = ['$scope'];
function KidCtrl($scope) {
$scope.numChildren = 2
$scope.children = [{
dob: "1/1/1990"
}, {
dob: "1/1/1995"
}];
$scope.onChange = function () {
$scope.children.length = $scope.numChildren;
}
}
app.directive('childDob', function () {
return {
restrict: 'E',
template: 'Child {{$index+1}} - date of birth: <input ng-model="child.dob" required/>'
}
});
})();

Looping though an object in Angular and using the key inside a ng-show

i am creating a simple Angular.js tabbing box which changes the box that is active accoring to a value 'tab' that is used inside ng-show on the elements.
This is working fine, however, at the moment I am writing all the HTML statically and I would rather cut down my code into a simple ng-repeat loop to loop through all the divs.
This is easy enough in PHP as I would use a foreach loop and use the key to generate the tab number, I just can't seem to do this in Angular. Here is my code at the moment:
<div id="services-box-nav">
<ul>
<li>Rewards</li>
<li>Community</li>
<li>Partners</li>
<li>Jobs</li>
<li>Volunteering</li>
<li>Feedback</li>
<li>Gallery</li>
</ul>
</div>
<div id="services-content-boxes">
<div ng-show="tab == 1">
<div class="row">
<div class="col-md-12">
<h3>{{serviceBoxes.rewards.title}}</h3>
</div>
</div>
<div class="row">
<div class="col-md-5">
{{serviceBoxes.rewards.text}}
</div>
<div class="col-md-7">
</div>
</div>
</div>
<div ng-show="tab == 2">dwd</div>
<div ng-show="tab == 3">d</div>
<div ng-show="tab == 4">df</div>
<div ng-show="tab == 5">gr</div>
<div ng-show="tab == 6">r</div>
<div ng-show="tab == 7">rg</div>
</div>
controller('servicesController', function($scope, $location, joomlaService) {
$scope.serviceBoxes = {};
joomlaService.getArticleDetails(21).then(function(articleReturnData) {
$scope.serviceBoxes.rewards = articleReturnData;
});
joomlaService.getArticleDetails(22).then(function(articleReturnData) {
$scope.serviceBoxes.community = articleReturnData;
});
joomlaService.getArticleDetails(23).then(function(articleReturnData) {
$scope.serviceBoxes.partners = articleReturnData;
});
joomlaService.getArticleDetails(24).then(function(articleReturnData) {
$scope.serviceBoxes.jobs = articleReturnData;
});
joomlaService.getArticleDetails(25).then(function(articleReturnData) {
$scope.serviceBoxes.volunteering = articleReturnData;
});
joomlaService.getArticleDetails(26).then(function(articleReturnData) {
$scope.serviceBoxes.feedback = articleReturnData;
});
joomlaService.getArticleDetails(27).then(function(articleReturnData) {
$scope.serviceBoxes.gallery = articleReturnData;
});
});
What I want to do is loop through the serviceBoxes object and dynamically create the ng-show condition (tab == i) using the key, which should increment each time (1, 2, 3, 4, etc). I don't know how I go about this using Angular. It would cut down my code considerably so feel it is necessary.
Can anyone point out how this is done?
Thanks
You can use angular-ui bootstrap Tabset directive.
<tabset>
<tab ng-repeat="serviceBox in serviceBoxes" heading="{{serviceBox.title}}" active="serviceBox.active">
{{serviceBox.text}}
</tab>
</tabset>
Thus your view is clean and tidy.
And your controller will look like:
controller('servicesController', function($scope, $location, joomlaService) {
$scope.serviceBoxes = [];
joomlaService.getArticleDetails(21).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(22).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(23).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(24).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(25).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(26).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(27).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
});
<ul>
<li ng-repeat="serviceBox in serviceBoxes">{{serviceBox.title}}</li>
</ul>
<div ng-repeat="serviceBox in serviceBoxes" ng-show="tab == {{selectedIndex}}">{{serviceBox.contents}}</div>
In your controller:
$scope.selectedIndex = 0; // Default selected index, use -1 for no selection
$scope.itemClicked = function ($index) {
$scope.selectedIndex = $index;
};
The ng-repeat directive loops through every element and makes a copy of the html element it's placed inside of. If there at 10 items to look through, you will have 10 html elements. It also you references to the index of the current element via $index.
ng-click will call the function on itemClicked(), passing in the current index through the $index reference that ng-repeat supplied. In our function we're using that parameter to set our $scope.selected to it.
I have tried creating something similar. Try below code
I have hardcoded mapTab array.You can populate myTab using the corresponding values from $scope
In controller-
$scope.tab;
$scope.mapTab=[{},{"1": "dwd"},{"2":"d"},{"3":"dwd"},{"4":"df"},{"5":"gr"},{"6":"r"},{"7":"rg"}];
In html--
<div ng-repeat="(key,val) in mapTab">
<div ng-repeat="prop in val">
<div ng-show="tab==key">{{prop}}</div>
</div>
</div>
</div>
Demo--http://jsfiddle.net/RahulB007/HB7LU/9348/

Resources