I have a simple angularjs application, in which I want to run a slider and the slider elements come from $http request.
Here is the code for reference:
var mainApp = angular.module("myapp", []);
mainApp.run(['$rootScope', '$http',
function($rootScope, $http) {
$http.post('process.php?ajax_type=getChild').success(function(data) {
if (data.success) {
console.log(data.child); // data received...
$rootScope.categories = data.child;
}
});
}]);
mainApp.controller('gridChildController', function($scope, $http, $rootScope) {
console.log($rootScope.categories); // this is also null....
$scope.brands = $rootScope.categories;
$scope.finished = function(){
jQuery('.brand_slider').iosSlider({
desktopClickDrag: true,
snapToChildren: true,
infiniteSlider: false,
navNextSelector: '.brands-next',
navPrevSelector: '.brands-prev',
lastSlideOffset: 3,
onSlideChange: function (args) {
}
});
};
});
Here is code of the template file:
<div ng-app="myapp">
<div ng-controller="gridChildController" class="brand_slider" >
<div class='slider'>
<div class="slide col-md-5ths col-sm-4 col-xs-12 text-center" ng-repeat="x in brands" ng-init="$last && finished()">
<img class="img-responsive center-block" ng-src="{{x.image}}" title="{{x.title}}" alt="{{x.title}}">
</div>
</div>
</div>
</div>
When I run this code, I get the data from the $http but ng-repeat doesn't work, and in the controller I get data null.
If you put something on $rootScope it will be also available on the child scopes. So you can bind straight to categories (no need to copy it to $scope.brands):
ng-repeat="x in categories"
Related
I'm studying AngularJS Services and I'm having a problem.
That's my Angular code:
var app = angular.module("todoListApp");
app.controller('MainController', MainController);
MainController.$inject = ['$scope'];
function MainController($scope, dataService){
$scope.helloConsole = dataService.helloConsole;
};
app.service('dataService', function(){
this.helloConsole = function(){
console.log("console services");
};
});
That's my HTML Code
<div ng-controller="MainController" class="list">
<div class="item" ng-class="{'editing-item' : editing, 'edited': todo.edited}" ng-repeat="todo in todos">
<div class="actions">
Edit
Save
Delete
</div>
</div>
</div>
I'm trying to make it so that when I click on Save, the console shows me "console services", but it's giving me an error:
angular.js:13424 TypeError: Cannot read property 'helloConsole' of undefined
Proper Angular Structure
you need to change the way you have written your code. It should look more like this
angular.module("todoListApp", [])
.controller('MainController', ['$scope', 'dataService', function($scope, dataService){
$scope.helloConsole = dataService.helloConsole;
}])
.service('dataService', [function(){
this.helloConsole = function(){
console.log("console services");
};
}]);
Also this is a 'data service' is this gettig data with a http call? Because if so then make a factory.
Controllers for business logic
Factories for data requests
Services for things like login
Directives for DOM manipulation
Filters for format
Return a singleton service object from angular.service's second function argument. Also, if you're explicit about the dependencies of your controller, thinks will work a lot clearer/better:
var app = angular.module("todoListApp", []);
app.controller('MainController', ['$scope', 'dataService', MainController]);
function MainController($scope, dataService){
$scope.helloConsole = dataService.helloConsole;
$scope.todos = [{txt:"todo 1"}, {txt:"todo 2"}];
}
app.service('dataService', function(){
return {
helloConsole: function(){
console.log("console services");
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
<div ng-app="todoListApp">
<div ng-controller="MainController" class="list">
<div class="item" ng-class="{'editing-item' : editing, 'edited': todo.edited}" ng-repeat="todo in todos">
{{todo.txt}}
<div class="actions">
Edit
Save
Delete
</div>
</div>
</div>
</div>
I rewrote this a little bit so it's easier to understand (for me at least).
I have added a "todos" array to your code just to make the ng-repeat fire.
var app = angular.module("todoListApp",[])
.service('dataService', function(){
this.helloConsole = function(){
console.log("console services");
};
})
.controller('MainController', [ '$scope', 'dataService',function ($scope,dataService) {
$scope.helloConsole = dataService.helloConsole;
$scope.todos = [ {
"todo":"1"
}
]
}])
;
I'm creating a small event app with angular for practicing. Currently i've created a application with Laravel 5.1 and returning some URL's with JSON. I load those URL's in my Factory for the events. Those events will be rendered with Angular. After they are rendered, a button with "Show info" will be placed and when you click at it, i want to call a function in the EventController so my $scope.event will receive the new data. My Controller has a function with $scope.getEvent(eventID); but i cant figure out how to run that function on click.
//Controller
app.controller('EventController', ['$scope', 'eventFactory', '$http', function ( $scope, eventFactory, $http )
{
eventFactory.getEvents(1).then(function(response){
$scope.events = response.events;
$scope.eventPaginator = response.pagination;
});
$scope.getEvent = function(value){
console.log('trigger');
eventFactory.getEvent(value).then(function(response){
$scope.event = response;
});
};
$scope.loadPage = function(page){
eventFactory.getEvents(page).then(function(response){
$scope.events = response.events;
$scope.eventPaginator = response.pagination;
});
};
}]);
//Directive
app.directive('event', function() {
return {
restrict: 'E',
scope: {
data: '=',
loadEvent: '&',
},
templateUrl: '/assets/website/angular/views/event.html',
link: function(scope, element){
scope.loadEvent(function(){
alert('Click')
});
},
};
});
//Factory
app.factory('eventFactory', ['$http', function ( $http )
{
return {
getEvents: function (page)
{
return $http.get('/api/v1/events?page='+page)
.then(function ( response )
{
return response.data;
});
},
getEvent: function (id)
{
return $http.get('/api/v1/event/'+id)
.then(function ( response )
{
return response.data;
});
}
};
}]);
//View
<div class="event">
<h2>[[data.event.title]] ID: [[data.event.id]]</h2>
<div class="event-image">
</div>
<div ng-click="loadEvent(data.event.id)">Click voor [[data.event.id]]</div>
</div>
//HTML code for the Laravel View
<div class="col-md-9" ng-controller="EventController">
<div class="btn btn-success" ng-click="getEvent(15)">Test</div>
<div class="row">
<h1 ng-bind="showEvent.event.title"></h1>
{#<div class="col-md-12">#}
{#<h1 class="page-header">Page Heading <small>Secondary Text</small></h1>#}
{#<div ng-controller="BannerController">#}
{#<ul rn-carousel rn-carousel-auto-slide="3" rn-carousel-transition="slide" rn-carousel-duration="1000" class="image carousel">#}
{#<li ng-repeat="banner in banners">#}
{#<img ng-src="[[banner.image]]" alt="" class="img-responsive">#}
{#</li>#}
{#</ul>#}
{#</div>#}
{#</div>#}
<div class="col-sm-12">
<div class="row">
<div class="col-sm-4" ng-repeat="event in events">
<h1>Een event</h1>
<event data="event"></event>
</div>
</div>
</div>
<div class="col-sm-12">
<h3>[[eventPaginator.total]]</h3>
<div class="pagination">
<div ng-repeat="n in [] | range:eventPaginator.total">
<button ng-click="loadPage(n+1)">[[n+1]]</button>
</div>
</div>
</div>
</div>
</div>
I think you wanted to call the parent controller function from the directive template with passing id parameter to it. For that you need to pass the method reference to the directive in by adding load-event attribute with getEvent(id) on the directive element.
Also you should remove the unwanted link which has wrong code in it.
//below code should remove from the directive.
scope.loadEvent(function(){
alert('Click')
});
Directive Template
<event data="event" load-event="getEvent(id)"></event>
Template
<div ng-click="loadEvent({id: data.event.id})">Click voor [[data.event.id]]</div>
Recently, I began to study Angular. So much I do not know. I'm trying to get json data from a php file to use within an Angular controller. But the data from php file does not exceed.
controllers.js:
app.controller('MainCtrl',['$scope', '$resource', '$http',
function($scope, $resource,$http) {
$http.get('/xbmc.php').success(function(data) {
$scope.data = data;
});
}]);
xbmc.php:
<?
include('sys/inc/config.inc.php');
include(SMARTY_DIR.'Smarty.class.php');
include(BASE_DIR .'sys/inc/classes.inc.php');
include(BASE_DIR .'sys/inc/init.inc.php');
include(BASE_DIR .'xbmcApi.php');
$jsonData = new xbmcApi($_GET['action']);
/**
if (MEGAKINO_LOGED)
{
**/
$json = $jsonData->getResult();
/**
}
else
$json = array('authStatus' => '0');
**/
echo json_encode($json);
?>
index.html:
<body ng-controller="MainCtrl">
<div class="wrapper">
<h2>{{title}}</h2>
<div class="row">
<div class="col-md-1 col-sm-2 col-xs-4" style="margin-top: 0.5%;" ng-repeat="item in data.items">
<div class="image" style="margin-bottom: 1%">
<a data-ng-href="#!/seasons/serie/{{item.id}}">
<img data-ng-src="/files/series/thumb-{{item.id}}.jpg" alt=""/>
</a>
</div>
<div class="info">
<a data-ng-href="#!/seasons/serie/{{item.id}}">
<b>{{item}}</b>
<u>Рейтинг: {{item.rate}}</u>
</a>
</div>
</div>
</div>
</div>
</body>
Your php code tells that your json will be build if a $_GET['action'] param is passed:
$jsonData = new xbmcApi($_GET['action']);
Yet, you are not passing any data as a query string from your angular controller. Try something like:
app.controller('MainCtrl',['$scope', '$resource', '$http',
function($scope, $resource,$http) {
$http({
url: '/xbmc.php',
method: "GET",
params: {action: 'some_action'}
}).success(function(data) {
$scope.data = data;
});
}]);
AS #CharlieH said, check for errors on your console:
app.controller('MainCtrl',['$scope', '$resource', '$http',
function($scope, $resource,$http) {
$http.get('/xbmc.php')
.then(function(response) {
$scope.data = response.data;
})
.catch (function(error) {
//check for errors here
console.log(error);
throw error;
});
}]);
Also the .success method has been deprecated. We should all be migrating to using .then and .catch. For more information on that see: Deprecation of the .success and .error methods in the $http service
Generally, what I want to do, is to initialize nested ng-controller inside ng-repeat using variable.
JSFiddle
JS
angular.module('app',[])
.controller('main',function($scope){
angular.extend($scope,{
name:'Parent Controller',
items:[
{name:'nested2'},
{name:'nested1'}
]
});
})
.controller('nested1',function($scope){
$scope.name = "Name1";
})
.controller('nested2',function($scope){
$scope.name = "Name2";
});
I want this:
<div ng-controller="main" ng-app='app'>
Nested: {{name}}
<div ng-controller="nested1">{{name}}</div>
<div ng-controller="nested2">{{name}}</div>
</div>
to become to something like this:
<div ng-controller="main">
Nested: {{name}}
<div ng-repeat="item in items">
<div ng-controller="item.name">{{name}}</div>
</div>
</div>
Problem: it does not work this way. Neither it works any other way, that I've tried after google'ing for an hour or so.
Is there any "legal" and nice way to achieve that at all?
There isn't a real way,using angular features it at this point, i suppose. You could create a directive and use un-documented dynamic controller feature controller:'#', name:'controllerName'. But this approach will not evaluate bindings or expressions that provide the controller name. What i can think of is a hack by instantiating a controller provided and setting it to the element.
Example:-
.directive('dynController', function($controller){
return {
scope:true, //create a child scope
link:function(scope, elm, attrs){
var ctrl =scope.$eval(attrs.dynController); //Get the controller
///Instantiate and set the scope
$controller(ctrl, {$scope:scope})
//Or you could so this well
//elm.data('$ngControllerController', $controller(ctrl, {$scope:scope}) );
}
}
});
And in your view:-
<div ng-controller="main">
<div ng-repeat="item in items">
Nested:
<div dyn-controller="item.name" ng-click="test()">{{name}}</div>
</div>
</div>
Demo
Note that i have changed the position of ng-controller from the element that does ng-repeat, since ng-repeat (1000) has higher priority than ng-controller (500), ng-repeat's scope will prevail and you end up not repeating anything.
While looking at it
Invested more couple hours into it, inspecting angular's sources etc.
The expression, given to ng-controller, is not being evaluated at all.
Here is best approach I've found:
HTML:
<div ng-controller="main">
Nested: {{name}}
<div ng-repeat="item in items">
<div ng-controller="nested" ng-init="init(item)">{{name}}</div>
</div>
</div>
JS:
angular.module('myApp', [])
.controller('main', function ($scope, $controller) {
angular.extend($scope, {
name: 'Parent Controller',
items: [
{name: 'nested2'},
{name: 'nested1'}
]
});
})
.controller('nested', function ($scope, $controller) {
angular.extend($scope, {
init: function (item) {
$controller(item.name, {'$scope': $scope});
}
});
})
.controller('nested1', function ($scope) {
$scope.name = 'test1';
})
.controller('nested2', function ($scope) {
$scope.name = 'test2';
});
In my project, I do an AJAX request using AngularJS who call another page that includes Angular directives (I want to make another AJAX call inside) but no interaction in loaded page.
I think new DOM isn't functionnal.. I'm trying the pseudo-code $apply unsuccessed.
Main.html :
<!DOCTYPE html>
<html data-ng-app="App">
<head></head>
<body >
<div data-ng-controller="editeurMenuMobile">
<ul>
<li data-ng-click="callMenu('FirstAjax.html')" > <!-- Work ! -->
<a href="">
<span>Modèles</span>
</a>
</li>
<li data-ng-click="callMenu('FirstAjax.html')"> <!-- Work ! -->
<a href="">
<span>Designs</span>
</a>
</li>
</ul>
<div data-ng-bind-html="data">
<!-- AJAX content -->
</div>
</div>
<!-- Javascript scripts -->
</body>
</html>
FirstAjax.html :
<div data-ng-controller="editeurActionAjax">
<div>
<button data-ng-click="callAction('SecondAjax.html')"> <!-- Doesn't work -->
Go
</button>
</div>
</div>
And my JS :
var App = angular.module('App', []);
App.controller('editeurMenuAjax', ['$scope', '$http', '$sce', function($scope, $http, $sce) {
$scope.callMenu = function(element) {
$http({method: 'GET', url: element}).
success(function(data) {
$scope.data = $sce.trustAsHtml(data);
}).
error(function() {
$scope.showAjaxError = true;
});
};
}
]);
App.controller('editeurActionAjax', ['$scope', '$http', '$sce', function($scope, $http, $sce) {
$scope.callAction = function(element) {
$http({method: 'GET', url: element}).
success(function(data) {
$scope.data = $sce.trustAsHtml(data);
}).
error(function() {
});
};
}
]);
Thank you for your help
From my point of view could the problem be because of the $scope?
your 2nd Controller don't have access to the same data variable.
Try to change the code to use $rootScope in both controllers instead of $scope, and see if it fix the problem.
Or
On your FirstAjax.html insert this:
<div data-ng-bind-html="data">
<!-- AJAX content -->
</div>
This should make a second data variable inside Scope of Controller 2, so that it can place the content.
I resolve my problem with this response.
My new JS :
App.directive('bindHtmlUnsafe', function( $compile ) {
return function( $scope, $element, $attrs ) {
var compile = function( newHTML ) { // Create re-useable compile function
newHTML = $compile(newHTML)($scope); // Compile html
$element.html('').append(newHTML); // Clear and append it
};
var htmlName = $attrs.bindHtmlUnsafe; // Get the name of the variable
// Where the HTML is stored
$scope.$watch(htmlName, function( newHTML ) { // Watch for changes to
// the HTML
if(!newHTML) return;
compile(newHTML); // Compile it
});
};
});
var App = angular.module('App', []);
App.controller('editeurMenuAjax', ['$scope', '$http', '$sce', function($scope, $http, $sce) {
$scope.callMenu = function(element) {
$http({method: 'GET', url: element}).
success(function(data) {
$scope.data = $sce.trustAsHtml(data);
}).
error(function() {
$scope.showAjaxError = true;
});
};
}
]);
App.controller('editeurActionAjax', ['$scope', '$http', '$sce', function($scope, $http, $sce) {
$scope.callAction = function(element) {
$http({method: 'GET', url: element}).
success(function(data) {
$scope.data = $sce.trustAsHtml(data);
}).
error(function() {
});
};
}
]);
And new Main.html :
<!DOCTYPE html>
<html data-ng-app="App">
<head></head>
<body >
<div data-ng-controller="editeurMenuMobile">
<ul>
<li data-ng-click="callMenu('FirstAjax.html')" > <!-- Work ! -->
<a href="">
<span>Modèles</span>
</a>
</li>
<li data-ng-click="callMenu('FirstAjax.html')"> <!-- Work ! -->
<a href="">
<span>Designs</span>
</a>
</li>
</ul>
<div data-bind-html-unsafe="data">
<!-- AJAX content -->
</div>
</div>
<!-- Javascript scripts -->
</body>
</html>
And FirstAjax.html :
<div data-bind-html-unsafe='dataAction' >
<div class="addRubrique">
<button data-ng-click="callAction('SecondAjax.html')">
Ajouter
</button>
</div>
</div>
BindHtmlUnsafe the directive re-compile the new DOM to Angular knows the DOM loaded AJAX