AngularJS slider - can't get directive to work - html

Hi I'm trying to make a slider I got off the internet to work, but, I keep getting errors. In gallery.html, when I put the slider element at the top I get nothing, when I put it at the bottom I get errors. The error is something along the lines
Error: [$compile:tplrt] http://errors.angularjs.org/1.4.8/$compile/tplrt?p0=slider&p1=partials%2Fgallery.html
Changed my code to match the suggestions in one of the comments.
I'm no longer getting the error to do with not have just 1 root element. Now, I can't get the next and previous to work. It just redirects me to the main page.
Note:
- gallery.html and slider.html are in a folder called partials
- all the images are in a folder called img
Thanks in advance!
index.html
<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
<!-- ANGULAR IMPORTS -->
<script type="text/javascript" src="js/angular.min.js"></script>
<script type="text/javascript" src="js/ui-router-master/release/angular-ui-router.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="https://code.angularjs.org/1.4.7/angular-animate.js"></script>
<!-- JS FILES -->
<script src="js/controller.js"></script>
<script src="js/directives.js"></script>
<link href='css/app.css' rel='stylesheet' type='text/css'>
</head>
<body class="container">
<div class="navbar">
<a class="brand" href="#">Quick Start</a>
<ul class="nav">
<li><a ui-sref="state1">State 1</a></li>
<li><a ui-sref="state2">State 2</a></li>
<li><a ui-sref="gallery">Gallery</a></li>
</ul>
</div>
<div class="dynamiccontent">
<div ui-view></div>
</div>
<!-- App Script -->
<script>
/** MAIN ANGULAR VAR */
var myapp = angular.module('myapp', [
/**IMPORT DEPENDENCIES*/
'ui.router',
'ngAnimate',
/**FILE DEPENDENCIES*/
'appController',
'slider.directive'
]);
/** UI-ROUTING */
myapp.config(function($stateProvider, $urlRouterProvider){
// For any unmatched url, send to /state1
$urlRouterProvider.otherwise("/state1")
$stateProvider
.state('state1', {
url: "/state1",
templateUrl: "partials/state1.html"
})
.state('state1.list', {
url: "/list",
templateUrl: "partials/state1.list.html",
controller: 'state1controller'
})
.state('gallery', {
url: "/gallery",
templateUrl: "partials/gallery.html",
controller: 'slidercontroller'
})
.state('state2', {
url: "/state2",
templateUrl: "partials/state2.html"
})
.state('state2.list', {
url: "/list",
templateUrl: "partials/state2.list.html",
controller: 'state2controller'
});
});
</script>
</body>
</html>
controller.js
var appController = angular.module('appController',[]);
appController.controller('state1controller', ['$scope', function($scope){
$scope.items = ["A", "List", "Of", "Items"];
}]);
appController.controller('state2controller', ['$scope', function($scope){
$scope.things = ["A", "List", "Of", "Items"];
}]);
appController.controller('slidercontroller', ['$scope', function($scope) {
$scope.pictures=[{src:'img1.png',title:'Pic 1'},{src:'img2.jpg',title:'Pic 2'},{src:'img3.jpg',title:'Pic 3'},{src:'img4.png',title:'Pic 4'},{src:'img5.png',title:'Pic 5'}];
}]);
directive.js
angular.module('slider.directive', [])
.directive('slider', function ($timeout) {
return {
restrict: 'AE',
replace: true,
scope:{
pictures: '='
},
link: function (scope, elem, attrs) {
scope.currentIndex=0;
scope.next=function(){
scope.currentIndex<scope.pictures.length-1?scope.currentIndex++:scope.currentIndex=0;
};
scope.prev=function(){
scope.currentIndex>0?scope.currentIndex--:scope.currentIndex=scope.pictures.length-1;
};
scope.$watch('currentIndex',function(){
scope.pictures.forEach(function(image){
image.visible=false;
});
scope.pictures[scope.currentIndex].visible=true;
});
/* Start: For Automatic slideshow*/
var timer;
var sliderFunc=function(){
timer=$timeout(function(){
scope.next();
timer=$timeout(sliderFunc,5000);
},5000);
};
sliderFunc();
scope.$on('$destroy',function(){
$timeout.cancel(timer);
});
/* End : For Automatic slideshow*/
},
templateUrl:'partials/slider.html'
}
});
gallery.html
<slider pictures="pictures"></slider>
slider.html
<div class="slider">
<div class="slide" ng-repeat="image in pictures">
<img ng-src="img/{{image.src}}"/>
</div>
<div class="arrows">
<img src="img/left-arrow.png"/>
<img src="img/right-arrow.png"/>
</div>
</div>

You are mixing several concerns here. partials/gallery.html is used as a template for your directive and your page. This leads to the directive being used itself in it's own template.
The solution is to remove your directive code from gallery.html and use it in a new file slider.html.
directive.js
.directive('slider', function ($timeout) {
return {
...
templateUrl:'partials/slider.html'
slider.html
<div class="slider">
<div class="slide" ng-repeat="image in images">
<img ng-src="img/{{image.src}}"/>
</div>
<div class="arrows">
<img src="img/left-arrow.png"/>
<img src="img/right-arrow.png"/>
</div>
</div>
gallery.html
<slider images="pictures"/>

First off - the error does have to do with the root element.
https://docs.angularjs.org/error/$compile/tplrt
Template for directive '{0}' must have exactly one root element. {1}
Now that you fixed that issue - your infinite loop is called because you're trying to populate the slider directive with gallery.html - but in that template, you're calling the slider directive. So that's an infinite loop.

Related

How to swap views in angularJS?

I am trying to create an angular application.
When the index.html page is loaded 2 links login and register are displayed.
When either login or register is clicked the entire view is replaced by the corresponding view.
1. Register/Login links should stay at the top and the corresponding view should be displayed below after clicking on them.
2. After successful authentication in login controller, The complete view including the login and register link should be replaced with menu-auth.html view.
I have tried using the below code, but still the 2 links disappear and login/register views appear.
Also after the http Post is fired in login controller, the menu-auth.html is displayed but appropriate css is not displayd, so I am not able to click the menu links.
I guess the menu-auth.html view is not placed in the view of index.html
index.html
<!doctype html>
<html>
<head>
<script src = "js/angular.min.js"></script>
<script src = "js/angular-ui-router.min.js"></script>
<script src = "app/app.js"></script>
<script src = "controller/login.js"></script>
<script src = "controller/register.js"></script>
<script src = "app/config.js"></script>
<style>.active { color: red; font-weight: bold; }</style>
</head>
<body>
<div ng-app="app">
<ui-view>
</ui-view>
</div>
</div>
</body>
</html>
I have two views
menu-unauth.html
<a ui-sref="login" ui-sref-active="active">Login</a>
<a ui-sref="register" ui-sref-active="active">Register</a>
<ui-view="unauth"></ui-view>
menu-auth.html
<a ui-sref=".nentry" ui-sref-active="active">Create Entry</a></br>
<a ui-sref=".ventry" ui-sref-active="active">View entry</a></br>
<a ui-sref=".logout" ui-sref-active="active">Logout</a></br>
<ui-view="auth"></ui-view>
config.js
app.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('unauth', {
url:'',
templateUrl: 'view/menu-unauth.html'
})
.state('unauth.login', {
url:'/login',
templateUrl: 'view/login.html',
controller: 'login'
})
.state('unauth.register', {
url:'/register',
templateUrl: 'view/register.html',
controller:'register'
})
.state('auth', {
url:'/menu',
templateUrl: 'view/menu-auth.html'
})
}]);
app.js
var app = angular.module("app", ['ui.router','ngCookies']);
login.js (Controller)
app.controller('login', function($scope,$http,$cookieStore,$state){
$scope.login=function(){
$scope.credentials={
UserName:$scope.email,
Password:$scope.password
};
$http({
method: 'POST',
url: 'test.com/sess',
data: $scope.credentials
}).then(function(response) {
$state.go('auth');
}
}
});
I made the following changes to (observe the ui-sref value changed to contain . dot)
menu-unauth.html
<a ui-sref=".login" ui-sref-active="active">Login</a>
<a ui-sref=".register" ui-sref-active="active">Register</a>
<ui-view></ui-view>
config.js
app.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('unauth', {
url:'',
templateUrl: 'view/menu-unauth.html'
})
.state('unauth.login', {
url:'/login',
templateUrl: 'view/login.html'
})
.state('unauth.register', {
url:'/register',
templateUrl: 'view/register.html'
})
}]);

AngularJS - How to get the name of the current HTML template file for the ui-view?

My app shows an HTML page with multiple views, and each view can be conditionally built from multiple HTML templates.
I want to edit each HTML file and add a few lines at the top, something like
<div ng-if="showFileNames”>
<hr>
<p>Start of file {{how do I get the file name}}</p>
<hr>
</div>
And maybe the same at the footer.
Thus, by setting $scope. showFileNames to true, I could switch the display of file names on/off and see how my page is actually composed (is this clear, or should I add some ascii art?).
I could just hard code {{how do I get the file name}} in each file, but doing it dynamically means that I can more easily add the code to each file, plus it guards against files being renamed.
Can it be done? If so, how?
[Update] I just realized that the question didn't explain well enough. Sorry.
I need to stress that part where I said
each view can be conditionally built from multiple HTML templates
While the view is state based, its contents are built from different <ng-include> files, based on data.
So, state A might include A.html, but, based on the data, that view might <ng-include> B.html, C.html and E.html, or it might <ng-include> F.html, G.html and H.htFl - and I want to show the file name of each at the head & foot of the part of the view shown by each file
Update: You may have templates loaded with ui-view and ng-include. The example given bottom of this answer has a nice generic directive to return the corresponding template name even though if you nested ui-view and ng-include together. Click through "Home", "About" and "Named View" link inside "About".
Few theory goes below,
If you use ui-view then you can try this with $state.current.templateUrl as below.
<div ng-if="showFileNames”>
<hr>
<p>Start of file {{$state.current.templateUrl}}</p>
<hr>
</div>
The above will work if you had defined your state as below,
.state('state1', {
url: '/state1',
templateUrl: 'partials/state1.html'
controller: 'State1Ctrl'
})
But if you had defined this as named views as below,
$stateProvider
.state('report',{
views: {
'filters': {
templateUrl: 'report-filters.html',
controller: function($scope){ ... controller stuff just for filters view ... }
}
}
}
})
Then, better you can have a method assigned with the $rootScope as below and pass the $state.current.views from the html to the function.
$rootScope.getTemplate = function(view) {
var keys = Object.keys(view);
if(keys.length === 0) return '';
return view[keys[0]].templateUrl;
};
and the html,
<div ng-if="showFileNames”>
<hr>
<p>Start of file {{getTemplate($state.current.views)}}</p>
<hr>
</div>
But you can have a look at the below generic directive which covers ui-view, nested ui-view, named ui-view and ng-include and even a bit of complex nesting with ui-view and ng-include.
Generic directive with an example page
Click through "Home", "About" and "Named View" link inside "About"
var app = angular.module('app', ['ui.router']);
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html',
controller: 'TestController'
})
.state('about', {
url: '/about',
templateUrl: 'about.html',
controller: 'TestController'
})
.state('about.named', {
url: '/named',
views: {
'named': {
templateUrl: 'named.html',
controller: 'TestController'
}
}
});
}
]);
app.controller('TestController', function($scope) {
});
app.directive('templateName', ['$state', function($state) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var templateName = $state.current.templateUrl;
var includesParent = $(element).closest('[ng-include]');
if(includesParent && includesParent.length > 0) {
if(includesParent.find('[ui-view]').length === 0) {
templateName = scope.$eval(includesParent.attr('ng-include'));
}
}
if(!templateName && $state.current.views) {
var uiViewParent = $(element).closest('[ui-view]');
var viewName = $state.current.views[uiViewParent.attr('ui-view')];
if(viewName) {
templateName = viewName.templateUrl;
}
}
element.html(templateName);
}
};
}]);
angular.bootstrap(document, ['app']);
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.min.js"></script>
<div>
<!-- NAVIGATION -->
<nav class="navbar navbar-inverse" role="navigation" ng-include="'nav.html'">
</nav>
<!-- MAIN CONTENT -->
<div class="container">
<!-- THIS IS WHERE WE WILL INJECT OUR CONTENT ============================== -->
<div ui-view></div>
</div>
<script type="text/ng-template" id="home.html">
<h3>Home Page</h3>
<p>Start of file: <span template-name></span></p>
</script>
<script type="text/ng-template" id="about.html">
<h3>About Page<h3>
<p>Start of file: <span template-name></span></p>
<div ng-include="'aboutUs.html'"></div>
</script>
<script type="text/ng-template" id="aboutUs.html">
<h3>About us<h3>
<p>Start of file: <span template-name></span></p>
<a ui-sref="about.named">Named View</a>
<div ui-view="named"></div>
</script>
<script type="text/ng-template" id="named.html">
<h3>Named View<h3>
<p>Start of file: <span template-name></span></p>
</script>
<script type="text/ng-template" id="nav.html">
<div class="navbar-header">
<a class="navbar-brand" ui-sref="#">Start of file: <span template-name></span></a>
</div>
<ul class="nav navbar-nav">
<li><a ui-sref="home">Home</a></li>
<li><a ui-sref="about">About</a></li>
</ul>
</script>
</div>

Unable to fetch data from controller in multiple html page in angularjs

I am trying to make a webpage.In that when a user login , a new html page("dashboard.html")opens in the view. This "dashboard.html" contains some links(links to other html pages).When user clicks on them a new html(say "page_3.html") page should open with data that is present in controller.this "page_3.html" is not fetching data from controller.Below is my code.
<!-- controller.js -->
var app = angular.module('myApp',[ 'ngRoute' ]);
app.config(function($routeProvider){
$routeProvider
.when('/',{
templateUrl: 'login.html'
})
.when('/dashboard',{
templateUrl: 'dashboard.html'
})
.when('/page_3',{
templateUrl: 'page_3.html'
})
.otherwise({
redirectTo : '/'
});
});
app.controller('app', function($scope, $location){
$scope.item = "test";
$scope.submit = function(){
$location.path('/dashboard');
}
};
});
<!DOCTYPE html>
<html>
<head>
<title>Project</title>
<script src="angular.js"></script>
<script src="angular-route.js"></script>
<script src="controller.js"></script>
</head>
<body ng-app= "myApp" ng-controller="app">
<div ng-view></div>
</body>
</html>
<!-- below is login.html page -->
<div ng-controller="app">
<form action="/">
<button type="button" ng-click="submit()">Login</button>
</form>
</div>
<!-- below is my dashboard.html page -->
<div ng-controller="app">
<h1>Page_3</h1>
<div><a href='page_3.html'>page_3</a></div>
</div>
<!-- below is page_3.html page -->
<div ng-controller="app">
<p>{{item}}</p>
</div>
result : {{item}}
May I suggest avoiding the ng-controller directive and rather use the controller config object on your router?
.when('/page_3',{
templateUrl: 'page_3.html',
controller: "app"
})
There are two main problems with your code:
Enable HTML 5 mode for pushState via $locationProvider for URLs like /dashboard and /page_3
Fix the problem where route is configured for /page_3 but having a a tag pointed to /page_3.html
To get a working example:
Add a base tag
<base href="/">
Enable html5 mode via locationProvider in a config block
$locationProvider.html5Mode(true);
Fix route in dashboard.html
<!-- below is dashboard.html page -->
<div ng-controller="app">
<h1>Page_3</h1>
<div><a href='page_3.html'>page_3</a></div>
</div>
Click here for the demo / jsbin.
Other/suggestions: as Zack Briggs have suggested; using controller syntax in routes would help you come up with better code structure / design in router config, directives, or components. Also putting everything in one place is often a bad idea for a growing project.

ng-click event inside the bootstrap modal not firing

I tried to use "ng-click" from angular into a html page and I managed. But if i try to use the same "ng-click" on the same function in a bootstrap modal code don't work anymore. Why. How to call mehod in the second case ?
This is my html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>title</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div ng-controller="MainController">
Call from file<br/>
Call from a pop-up
</div>
<div class="modal fade" id="about" role="dialog">
<div class="modal-dialog" modal-sm>
<div class="modal-content">
<div class="modal-header">
<h4>Pop-up head.</h4>
</div>
<div class="modal-body">
<h4>Pop-up body.</h4>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="first()">Send</button>
</div>
</div>
</div>
</div>
</body>
</html>
And this is my script
var myApp = angular.module('myApp', []);
myApp.controller("MainController", function($scope){
$scope.val= 1
$scope.even= false
$scope.increment = function(){
$scope.val +=1
$scope.even = ($scope.val%2 == 0)?true:false;
//$scope.even = $scope.val%2 == 0
}
$scope.first = function(){
alert("work");
}
})
The reason is that when the modal shows up the processing of all angular directives is already over. Hence the ng-click attribute on the template of modal that is going to be appended to the DOM later on makes no difference.
Generally you would like the HTML to be compiled with a the correct scope.
If you don't want to get into details of this, use Angular UI for Bootstrap
This will give you nice directives and services for bootstrap widgets.
There is a $modal service that can be used just like the $http service which returns a promise.
Here also you can have callbacks for events when modal disappears or closes.
There is sample code in the example. Here is how a function that will bring up a modal would look like:
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};

AngularJS-Render HTML embed codes as a layout

I would like to ask, I am trying to make a simple code which is to render out the YouTube's embed sharing code given I am using ng-repeat to loop through multiple inputs but i cant seem to get the proper render instead what I have got is text. How should I make it into a proper HTML output?
Below is the plunkr file I made as an example.
Thank you
Fo this purpose i would make some changes and approach in another way for your case:
Fixed here http://plnkr.co/edit/COnvjvoaYV643oQ46p9B?p=preview
JS
var app = angular.module('myApp', []);
app.config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'https://www.youtube.com/**'
]);
});
app.controller('videoController', ['$scope',
function MyCtrl($scope) {
$scope.product = {
name: 'some name',
description: 'some description',
media: [{
src: 'pbuGSt3Hb8k'
},{
src: 'y_o-ULSWWng'
}]
};
$scope.getIframeSrc = function(src) {
return 'https://www.youtube.com/embed/' + src;
};
}
]);
HTML
<html ng-app="myApp">
<head>
<script src="https://code.angularjs.org/1.2.1/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="videoController">
<div ng-repeat="media in product.media">
<div class="thumbnail">
<div class="video-container">
<iframe width="560" height="315" ng-src="{{getIframeSrc(media.src)}}" frameborder="0 " allowfullscreen></iframe>
</div>
</div>
</div>
</body>
</html>
use ng-bind-html like this:
<body ng-app="videoGall">
<div ng-controller="topicVideoCtrl">
<div ng-repeat="video in videos"><div ng-bind-html="makeTrust(video.url)"></div> </div>
</div>
</body>
and
videoGall.controller('topicVideoCtrl', function ($scope, $http,$sce) {
$scope.makeTrust=function(html){return $sce.trustAsHtml(html);};
$scope.videos = [
{"url":"<iframe width=\"560\" height=\"315\" src=\"\/\/www.youtube.com\/embed\/pbuGSt3Hb8k\" frameborder=\"0\" allowfullscreen><\/iframe>"},
{"url":"<iframe width=\"560\" height=\"315\" src=\"\/\/www.youtube.com\/embed\/y_o-ULSWWng\" frameborder=\"0\" allowfullscreen><\/iframe>"}];
});