Probably the question is not phrased correctly . But here is what I am trying to do .
I have a navbar defined with countries array that contains the countries' names and coordinates.
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Welcome to the world of directives!</a>
</div>
<ul class="nav navbar-nav">
<li ng-repeat="countryTab in countries" ng-click="itemClicked(countryTab.label)" style="cursor:pointer">
<a>{{countryTab.label}}</a>
<country-tab-bar country="selectedCountry"></country-tab-bar>
</li>
</ul>
</div>
</nav>
<script>
var app = angular.module('app',[]);
app.controller('appCtrl',function($scope){
$scope.countries = [{
id: 1,
label: 'Italy',
coords: '41.29246,12.5736108'
}, {
id: 2,
label: 'Japan',
coords: '37.4900318,136.4664008'
}, {
id: 3,
label: 'USA',
coords: '37.6,-95.665'
}, {
id: 4,
label: 'India',
coords: '20.5937,78.9629'
}];
});
</script>
Now country-tab-bar is the directive that has the template that shows the name and the map using the coordinates defined in the array.
I tried
app.directive('countryTabBar',function(){
return {
restrict: 'E',
scope:{
country: '='
},
template: '<div>'+
' <div>Italy</div>'+
' <br/>'+
' <img ng-src="https://maps.googleapis.com/maps/api/staticmap?center={{country.coords}}&zoom=4&size=800x200"> '+
'</div>',
link : function(scope,elem,attrs){
scope.itemClicked = function(value){
scope.selectedCountry = value;
}
}
}
});
But nothing happens on click of the country names.
UI for now is screwed up.
What needs to be done to fix the same?
Please suggest .
The map should only appear after clicking a name, not before.
Some minor changes in your code and it is working. See the comments below.
WORKING FIDDLE
//HTML
<div ng-app="app">
<div ng-controller='appCtrl'>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Welcome to the world of directives!</a>
</div>
<ul class="nav navbar-nav">
<!-- pass country to itemClicked function defined into controller -->
<li ng-repeat="country in countries" ng-click="itemClicked(country)" style="cursor:pointer">
<a>{{country.label}}</a>
</li>
<!-- directive moved outside the ng-repeat -->
<country-tab-bar country="selectedCountry"></country-tab-bar>
</ul>
</div>
</nav>
<div>
</div>
//app
var app = angular.module('app',[]);
//controller
app.controller('appCtrl',function($scope){
$scope.countries = [{
id: 1,
label: 'Italy',
coords: '41.29246,12.5736108'
}, {
id: 2,
label: 'Japan',
coords: '37.4900318,136.4664008'
}, {
id: 3,
label: 'USA',
coords: '37.6,-95.665'
}, {
id: 4,
label: 'India',
coords: '20.5937,78.9629'
}];
// function to select the country (receive de full object as parameter)
$scope.itemClicked = function(selected){
// set the object needed by the directive
$scope.selectedCountry = selected
}
});
//directive
app.directive('countryTabBar',function(){
return {
restrict: 'E',
scope:{
country: '='
},
template: '<div>'+
' <br/>'+
' <img ng-src="https://maps.googleapis.com/maps/api/staticmap?center={{country.coords}}&zoom=4&size=800x200"> '+
'</div>',
link : function(scope,elem,attrs){
}
}
});
Inside
Where is "selectedCountry" defined
I think what you are trying to do is this:
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Welcome to the world of directives!</a>
</div>
<ul class="nav navbar-nav">
<li ng-repeat="countryTab in countries" ng-click="countryTab.showProperty = !countryTab.showProperty" style="cursor:pointer">
<a>{{countryTab.label}}</a>
<country-tab-bar country="countryTab" ng-show="countryTab.showProperty"></country-tab-bar>
</li>
</ul>
</div>
</nav>
<script>
var app = angular.module('app',[]);
app.controller('appCtrl',function($scope){
$scope.countries = [{
id: 1,
label: 'Italy',
coords: '41.29246,12.5736108',
showProperty: false
}, {
id: 2,
label: 'Japan',
coords: '37.4900318,136.4664008',
showProperty: false
}, {
id: 3,
label: 'USA',
coords: '37.6,-95.665',
showProperty: false
}, {
id: 4,
label: 'India',
coords: '20.5937,78.9629',
showProperty: false
}];
});
</script>
app.directive('countryTabBar',function(){
return {
restrict: 'E',
scope:{
country: '='
},
template: '<div>'+
' <div>Italy</div>'+
' <br/>'+
' <img ng-src="https://maps.googleapis.com/maps/api/staticmap?center={{country.coords}}&zoom=4&size=800x200"> '+
'</div>'
}
});
Simply hide all country-tab-bar elements using ng-show directive which uses new property that if its true the tab is shown if its false its hidden.
the ng-click is assigned to the li element which includes both the button to click and the country-tab-bar itself. If you want to close it only on the button click move the ng-click directive inside the <a> element
Related
I have JSON:
$scope.allTags=[
{id: 1, name: 'name1', description: 'description1', title: 'title1'},
{id: 2, name: 'name2', description: 'description1', title: 'title1'},
{id: 3, name: 'name3', description: 'description2', title: 'title2'},
{id: 4, name: 'name4', description: 'description2', title: 'title2'},
{id: 5, name: 'name5', description: 'description3', title: 'title3'},
{id: 6, name: 'name6', description: 'description3', title: 'title3'},
{id: 7, name: 'name7', description: 'description3', title: 'title3'},
];
And I need to create BS accordion like this:
<a data-toggle="collapse" data-parent="#tags-accordion" href="#col_Iesaukumi1">Title1</a></br>
<div id="col_Iesaukumi1" class="collapse">
<span>name1</span><span>name2</span>
</div>
<a data-toggle="collapse" data-parent="#tags-accordion" href="#col_Iesaukumi2">Title2</a></br>
<div id="col_Iesaukumi2" class="collapse">
<span>name3</span><span>name4</span>
</div><a data-toggle="collapse" data-parent="#tags-accordion" href="#col_Iesaukumi3">Title3</a></br>
<div id="col_Iesaukumi3" class="collapse">
<span>name5</span><span>name6</span>span>name7</span>
</div>
And its killing me. I am new to angular and strugle with this task. In plain JS I did something like this:
var prev = null;
var counter = 1;
for(var i = 0; i < allTags.length; i++){
if(prev != allTags[i].title){
if(prev != null){
html += '</div>';
}
html += '<a data-toggle="collapse" data-parent="#tags-accordion" href="#col_collapse'+counter+'">'+allTags[i].title+'</a><i class="fa fa-info-circle" aria-hidden="true"></i></br>';
html+='<div id="col_collapse'+counter+'" class="collapse">';
prev = allTags[i].title;
counter++;
}
html += '<span class="tagi" data-type="tags" data-value="'+allTags[i].id+'">'+allTags[i].name+'</span>';
}
html += '</div>';
However I can not understand how use this tech with angular.
use this
<a ng-repeat-start="tag in allTags | unique:'description'" data-toggle="collapse" data-parent="#tags-accordion" href="#col_Iesaukumi{{$index}}">
{{tag.title}}
</a></br>
<div ng-repeat-end id="col_Iesaukumi{{$index}}" class="collapse">
<span ng-repeat="n in allTags" ng-if="tag.title===n.title">
{{n.name}}
</span>
</div>
the first loop is looping on all unique allTags based on their description
the second inner loop loops on allTags and gets the tag which has the same title as the outer loop to display the name
notice the $index is used in loops to distinct each iterate to provide a diffrent id for each one
i didn`t test the above code but the logic is like that
Edit
unique filter is an add-on in angular-ui solved here
You can simply use the ngRepeat directive like so:
<div class="panel panel-default" ng-repeat="tag in allTags track by $index">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{tag.id}}" aria-expanded="false" aria-controls="collapse{{tag.id}}">
{{tag.title}}
</a>
</h4>
</div>
<div id="collapse{{tag.id}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
<p>{{tag.name}}</p>
<p>{{tag.description}}</p>
</div>
</div>
</div>
This way you loop through each tag in allTags and can then access the value of each tag using the double curly brace notation {{ }}.
Here is a working example:
// app.js
(function() {
'use strict';
angular.module('app', []);
})();
// main.controller.js
(function() {
angular.module('app').controller('MainController', MainController);
MainController.$inject = ['$scope'];
function MainController($scope) {
$scope.allTags = [{
id: 1,
name: 'name1',
description: 'description1',
title: 'title1'
},
{
id: 2,
name: 'name2',
description: 'description2',
title: 'title2'
},
{
id: 3,
name: 'name3',
description: 'description3',
title: 'title3'
},
{
id: 4,
name: 'name4',
description: 'description4',
title: 'title4'
},
{
id: 5,
name: 'name5',
description: 'description5',
title: 'title5'
},
{
id: 6,
name: 'name6',
description: 'description6',
title: 'title6'
},
{
id: 7,
name: 'name7',
description: 'description7',
title: 'title7'
},
];
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div ng-app="app" ng-controller="MainController as MainCtrl">
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<div class="panel panel-default" ng-repeat="tag in allTags track by $index">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{tag.id}}" aria-expanded="false" aria-controls="collapse{{tag.id}}">
{{tag.title}}
</a>
</h4>
</div>
<div id="collapse{{tag.id}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
<p>{{tag.name}}</p>
<p>{{tag.description}}</p>
</div>
</div>
</div>
</div>
</div>
Below is my code,
i need to change the maintitle dynamically in h2 tag on click of navigation (navlinks) through angularJS.
Thanks in advance..
var portfolioApp = angular.module('portfolioApp', []);
portfolioApp.controller('navCtrl', ['$scope', '$location', function ($scope, $location) {
$scope.navLinks = [{
Title: 'home',
LinkText: 'Home'
}, {
Title: 'about',
LinkText: 'About Us'
}, {
Title: 'portfolio',
LinkText: 'Portfolio'
}, {
Title: 'contact',
LinkText: 'Contact Us'
}];
$scope.navClass = function (page) {
var currentRoute = $location.path().substring(1) || 'home';
return page === currentRoute ? 'active' : '';
};
$scope.maintitle = "Any Title";
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
<div ng-app="portfolioApp" ng-controller="navCtrl">
<h2>{{maintitle}}</h2>
<header class="well sidebar-nav">
<ul class="nav nav-list">
<li ng-repeat="navLink in navLinks" ng-class="navClass('{{navLink.Title}}')">
<a href='#/{{navLink.Title}}'>{{navLink.LinkText}}</a>
</li>
</ul>
</header>
</div>
<div ng-app="portfolioApp">
<div ng-controller="navCtrl">
<h2>{{maintitle}}</h2>
<header class="well sidebar-nav">
<ul class="nav nav-list" >
<li ng-repeat="navLink in navLinks" ng-class="navClass('{{navLink.Title}}')">
<a href='#/{{navLink.Title}}'>{{navLink.LinkText}}</a>
</li>
</ul>
</header>
<div>
</div>
and use
$scope.maintitle = 'title'
Check Out This:
var portfolioApp = angular.module('portfolioApp', []);
portfolioApp.controller('navCtrl', ['$scope', '$location', function ($scope, $location) {
$scope.maintitle = "Some Thing";
$scope.navLinks = [{
Title: 'home',
LinkText: 'Home'
}, {
Title: 'about',
LinkText: 'About Us'
}, {
Title: 'portfolio',
LinkText: 'Portfolio'
}, {
Title: 'contact',
LinkText: 'Contact Us'
}];
$scope.navClass = function (page) {
var currentRoute = $location.path().substring(1) || 'home';
return page === currentRoute ? 'active' : '';
};
$scope.goToLink = function(navlink){
$scope.maintitle = navlink.Title;
// fix location service accordin to your requirment
$location.path(navlink.Title);
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
<div ng-app="portfolioApp">
<header class="well sidebar-nav">
<ul class="nav nav-list" ng-controller="navCtrl">
<h2>{{maintitle}}</h2>
<li ng-repeat="navLink in navLinks" ng-class="navClass('{{navLink.Title}}')">
<a ng-click="goToLink(navLink)">{{navLink.LinkText}}</a>
</li>
</ul>
</header>
</div>
$scope.maintitle = "text you want";
EDIT: It won't work since it is out of controller. I can advise carrying it into controller, making another controller or searching for ways of manipulating items that are out of controller.
So I'm currently attempting to dynamically create accordions which expand to a ui-grid containing some data. The issue is that if I do not expand the accordions within a few seconds of the page loading the ui-grid is blank. The outline of where the table should be exists but there is no data being displayed. I say being displayed because the data itself is in the html. It seems like its hidden by the accordion? When I resize the browser window the data appears though. Sorry if this is not detailed enough or I missed obvious debugging steps, I'm new to js/angular and to html. Below is my HTML code
<div ng-controller="TestController as test">
<script type="text/ng-template" id="group-template.html">
<div class="panel-heading">
<h4 class="panel-title" style="color:#fa39c3">
<a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading">
<span uib-accordion-header ng-class="{'text-muted': isDisabled}">
TEST
</span>
</a>
</h4>
</div>
<div class="panel-collapse collapse" uib-collapse="!isOpen">
<div class="panel-body" style="text-align: right" ng-transclude></div>
</div>
</script>
<uib-accordion close-others="oneAtATime">
<div ng-repeat="model in myData" track by $index>
<div uib-accordion-group class="panel-default" is-open="isOpen">
<uib-accordion-heading>
Test Model {{$index}} <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': isOpen, 'glyphicon-chevron-right': !isOpen}"></i>
</uib-accordion-heading>
<div id="grid[$index]" ui-grid="gridOptions[$index]" ui-grid-edit class="grid" style="clear:both"></div>
<br />
<strong>Last Cell Edited:</strong>{{msg[$index]}}<br />
<button>Commit Changes</button>
</div>
</div>
</uib-accordion>
and my angular
(function () {
var app = angular
.module('testApp', ['ui.grid', 'ui.grid.edit', 'ui.bootstrap', 'ngAnimate'])
.controller('TestController', TestController);
TestController.$inject = ['$scope', 'uiGridConstants'];
function TestController ($scope, uiGridConstants) {
$scope.oneAtATime = false;
$scope.myData = myData;
$scope.msg = [];
$scope.gridOptions = [];
$scope.getGridOptions = function (index) {
$scope.gridOptions[index] ={
showColumnFooter: true,
columnDefs: [
{ field: 'ticker', enableCellEdit: false, width: '33%' },
{ field: 'current_w', aggregationType: uiGridConstants.aggregationTypes.sum, enableCellEdit: false, width: '33%' },
{ field: 'new_w', aggregationType: uiGridConstants.aggregationTypes.sum, width: '33%' }
],
data: myData[index],
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
gridApi.edit.on.afterCellEdit($scope, function (rowEntity, colDef, newValue, oldValue) {
$scope.msg[index] = 'Edited Ticker:' + rowEntity.ticker + ' Column:' + colDef.name + ' newValue:' + newValue + ' oldValue:' + oldValue;
$scope.$apply();
})
}
}
};
for (i = 0; i < Object.keys($scope.myData).length; i++) {
$scope.getGridOptions(i);
console.log($scope.gridOptions[i]);
};
console.log($scope.gridOptions[1]);
};
var myData = [
[{ ticker: 'TICKER', current_w: 5, new_w: 4, },
{ ticker: 'TICKER 2', current_w: 3, new_w: 2, },
{ ticker: 'TICKER 3', current_w: 7, new_w: 0, }],
[{ ticker: 'TICKER', current_w: 5, new_w: 4, },
{ ticker: 'TICKER 2', current_w: 3, new_w: 2, },
{ ticker: 'TICKER 3', current_w: 7, new_w: 5, }]
];
})();
I would take a stab at this and say that you may want to add a ng-if="isOpen" to the ui-grid. So something like below should fix your problem.
<div id="grid[$index]" ui-grid="gridOptions[$index]" ui-grid-edit class="grid" style="clear:both" ng-if="isOpen"></div>
I was having issues with my grid displaying as well, and ensuring that the grid only appears when it is absolutely ready fixed the problem. The ui-grid documentation goes over this concept of a hidden grid at http://ui-grid.info/docs/#/tutorial/108_hidden_grids. They also have a plnkr that you can follow at http://plnkr.co/edit/LtpFnDUTofuxitb4Vh9x?p=preview. I hope this helps!
I've created a simple app that should iist each item from a model in a list, created using a javascrit template.
Fiddle
Html:
<div id="tagsList" class="box">
<div class="box-head">
<h2 class="left">Tags</h2>
</div>
<div class="box-content">
<input type="text" placeholder="Add New Tag" />
<button>+ Add</button>
<div data-bind="template: 'tagsTempl'"></div>
</div>
</div>
<script id="tagsTempl" type="text/html">
<ul>
{{each tags}}
<li class="tagItem">
<span>${Name}</span>
<div>
Edit
Delete
</div>
</li>
{{/each}}
</ul>
</script>
Javascript:
$(function () {
//$("#tagDialog").hide();
var data = [
{ Id: 1, Name: "Ball Handling" },
{ Id: 2, Name: "Passing" },
{ Id: 3, Name: "Shooting" },
{ Id: 4, Name: "Rebounding" },
{ Id: 5, Name: "Transition" },
{ Id: 6, Name: "Defense" },
{ Id: 7, Name: "Team Offense" },
{ Id: 8, Name: "Team Defense" }
];
var viewModel = {
tags: ko.observableArray(data),
tagToAdd: ko.observable(""),
addTag: function() {
this.tags.push({ Name: this.tagToAdd() });
}
}
ko.applyBindings(viewModel)
});
Output of list:
{{each tags}}
${Name}
Edit Delete
{{/each}}
The scripts file is accessible through viewing source. I'm not sure where my error is. Any help?
I updated your fiddle. Now it is working like you want it to: The list of tags is being rendered using the knockout standard method as described in the docs.
HTML
<ul data-bind="template: {name: 'tagsTempl', foreach: tags}"></ul>
Template
<script id="tagsTempl" type="text/html">
<li class="tagItem">
<span data-bind="text: Name"></span>
<div>
Edit
Delete
</div>
</li>
</script>
Also I connected the viewmodel to the view.
For example:
<button data-bind="click: addTag">+ Add</button>
You simply forgot most of it. I suggest you follow the interactive tutorials on how to do this.
My custom directive is not working:
html:
<body ng-controller="StoreController as store">
<ul class="list-group">
<li class="list-group-item" ng-repeat="product in store.products">
<div>
<h3>
<product-title></product-title>
</h3>
...
javascript.app:
...
app.directive('productTitle', function(){
return {
restrice: 'E',
templateUrl: 'product-title.html'
};
});
...
and my product-title.html:
{{product.name}}
<em class="pull-right"> {{product.price | currency}}</em>
in my html page i cant see the product name and product price.
I am new in this subject :)
what should i do to make it work?
please help me.
++thanks everyone for yours answers, it is works! i tried for 3 days to find an answer.. and you did it in 5 min.. thanks! :)++
Couple of issues:
restrict is spelled wrong
Templates for html should have one root, so you should do something like this
<div>
{{product.name}}
<em class="pull-right"> {{product.price | currency}}</em>
</div>
Here is the complete running code for your directive in this JSBin
JS
angular
.module('app', [])
.controller('AppController', function ($scope) {
$scope.store = {
products: [
{ id: 1, price: 132, name: 'abc' },
{ id: 2, price: 127, name: 'def' },
{ id: 3, price: 112, name: 'mno' },
{ id: 4, price: 145, name: 'xyz' }
]
};
})
.directive('productTitle', function(){
return {
restrict: 'E',
templateUrl: 'product-title.html'
};
});
HTML
<div ng-controller='AppController'>
<ul class="list-group">
<li class="list-group-item" ng-repeat="product in store.products">
<h3>
<product-title></product-title>
</h3>
</li>
</ul>
</div>
<script id="product-title.html" type="text/ng-template">
{{product.name}}
<em class="pull-right"> {{product.price | currency}}</em>
</script>