Controller as syntax issues - javascript

I'm trying to use the Controller as syntax but I can't manage to make it work.
For example, here is a working code :
View :
<div ng-controller="ProjectsController">
Projects view : <br />
{{ projectsData }}
</div>
Controller :
angular.module('app')
.controller('ProjectsController', function($scope, Projects) {
Projects.get().then(function(result) {
$scope.projectsData = result.data;
});
});
And here is the Projects factory :
angular.module('app')
.factory('Projects', function($http) {
return {
get: function() {
return $http.get('http://localhost:8000/api/catalog/projects');
}
};
});
This way is working, using the normal syntax for controller and the $scope object inside of it.
But I can't get it to work when I'm using the Controller as syntax, like the following :
View :
<div ng-controller="ProjectsController as p">
Projects view : <br />
{{ p.projectsData }}
</div>
For the controller I tried :
angular.module('app')
.controller('ProjectsController', function(Projects) {
Projects.get().then(function(result) {
this.projectsData = result.data;
});
});
but also :
angular.module('app')
.controller('ProjectsController', function($scope, Projects) {
Projects.get().then(function(result) {
$scope.projectsData = result.data;
});
this.projectsData = $scope.projectsData;
});
But none of it worked, I had nothing in the view for {{ projectsData }}.
However, when I tried to test this as the controller using Controller as syntax :
angular.module('app')
.controller('ProjectsController', function($scope, Projects) {
Projects.get().then(function(result) {
$scope.projectsData = result.data;
});
console.log($scope.projectsData);
this.projectsData = "TEST";
});
I had my "TEST" displayed in the view, and $scope.projectsData was undefined.
So how can I set my controller in order to access it properly using the Controller as syntax ?

The problem is you need to store a reference of this in controller.
When you try to use this in a callback it has a different context
angular.module('app')
.controller('ProjectsController', function(Projects) {
var vm = this;
Projects.get().then(function(result) {
vm.projectsData = result.data;
});
});

Related

Using AngularJS with a factory and a Controller

I'm trying to do the following:
When a user accesses "localhost/people/:id", the information about the respective person is taken from a MongoDB and displayed via Angular.
I have my api, which works perfectly fine, I've double-checked.
I'm using the latest AngularJS (1.4.9) and the new Router (angular-new-router or ngNewRouter).
I have an Angular module:
var personModule = angular.module('app.personDetailed', []);
a factory:
personModule.factory('personService', ['$http', function($http) {
return {
get : function(id) {
return $http.get('/api/people/' + id);
}
}
}]);
and a controller:
personModule.controller('PersonDetailedController', ['$routeParams', '$scope', 'personService', PersonDetailedController]);
function PersonDetailedController($routeParams, $scope, personService) {
var id = $routeParams.id;
personService.get(id).then(function(res) {
$scope.item = res.data;
});
}
This all should be displayed in this view:
<div data-ng-controller="PersonDetailedController">
<h2>{{ item }}</h2>
</div>
(yes, I'm not bothering trying to parse json yet).
The problem is, I am unable to use both $scope and $routeParams at the same time. I can only have one or the other. If I use both, the $scope works fine, but the $routeParams is empty.
Here's the main controller, just in case:
var appModule = angular.module('app', ['app.main', 'app.personDetailed', 'ngNewRouter', 'ngResource']);
appModule.controller('AppController', ['$router', AppController]);
function AppController($router) {
$router.config([
{ path: '/', component: 'main'}
{ path: '/people/:id', component: 'personDetailed'}
]);
}
Seems the new router does away with $scope and binds to the controller instance in the template instead.
Looks like you should use this instead
personModule.controller('PersonDetailedController', ['$routeParams', 'personService', PersonDetailedController]);
function PersonDetailedController($routeParams, personService) {
var personDetailed = this,
id = $routeParams.id;
personService.get(id).then(function(res) {
personDetailed.item = res.data;
});
}
and your view (do not use ng-controller)
<h2>{{ personDetailed.item }}</h2>

Angular Directive update view from template url

I have started learning angularjs recently and I am doing some stuff. I tried to use this actice example, especially 3 example. I tried to read from tempate files by their url but I couldn't. I got bellow code (here only peace of code which I changed):
var app = angular.module('app', []);
app.value('MultiViewPaths',
{'/' : {
content : {
templateUrl : './templates/_header.html'
},
secondaryContent : {
templateUrl : './templates/_secondaryContent.html',
controller : 'ListUsersCtrl'
}
},
'/cats' : {
content: {
templateUrl : 'templates/_headerCats.html',
controller : 'ListCatsCtrl'
},
secondaryContent : {
templateUrl : 'templates/_secondaryContentCats.html',
controller : 'CatOfTheMinuteCtrl'
}
}
});
app.directive("ngMultiView", ['$rootScope', '$compile', '$controller', '$location', 'MultiViewPaths','$templateCache', function($rootScope, $compile, $controller, $location, MultiViewPaths, $templateCache){
var getTemplate = function(templateUrl) {
console.log(templateUrl)
var template = $templateCache.get(templateUrl);
console.log(template)
return template
}
return {
terminal: true,
priority: 400,
transclude: 'element',
compile : function(element, attr, linker){
return function(scope, $element, attr) {
var currentElement,
panel = attr.ngMultiView;
$rootScope.$on('$locationChangeSuccess', update);
update();
// update view
function update(evt, newUrl, oldUrl){
if(!newUrl){ return }
var url = newUrl.match(/#(\/.*)/),
match, template, controller;
match = url ? MultiViewPaths[url[1]] : MultiViewPaths['/'];
template = getTemplate(match[panel].templateUrl);
console.log(template)
controller = match[panel].controller;
if(template){
var newScope = scope.$new(),
locals = {},
newController = controller;
linker(newScope, function(clone){
clone.html(template);
$element.parent().append(clone);
if(currentElement){
currentElement.remove();
}
var link = $compile(clone.contents());
currentElement = clone;
if (newController) {
locals.$scope = newScope;
var controller = $controller(newController, locals);
clone.data('$ngControllerController', newController);
clone.children().data('$ngControllerController', newController);
}
link(newScope);
newScope.$emit('$viewContentLoaded');
});
}else{
//cleanup last view
}
}
}
}
}
}]);
Other thing the same with example. I could not read templates inner html. Can anyone help me ?
I would recommend using uiRouter rather than ngRouter. With uiRouter you do not need to create a directive to handle changing the view for different URL parameters.
They give an example of how to do this using the $stateProvider here http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider
templateUrl: function(params) {
return myTemplates[params.pageId]; }

Angular: using transclude with ng-bind-html

I have the following angular setup:
var app = angular.module('app', []);
app.filter('unsafe', function($sce) {
return $sce.trustAsHtml;
});
app.controller('SearchController', ['$scope', '$http', function($scope, $http) {
$scope.searchString = '';
$scope.searchType = 'Artist';
$scope.updateHtml = function() {
$http.get('/search', {
params: {
searchString: $scope.searchString,
searchType: $scope.searchType
}
}).success(function(data) {
$scope.html = data;
}).error(function(err){
$scope.html = err;
});
};
$scope.updateHtml();
}]);
app.directive('searchDirective', function() {
return {
restrict: 'A',
transclude: true,
template: '<div ng-bind-html="html | unsafe" ng-transclude></div>'
};
});
It pulls raw html markup through ajax in the controller and stores it in #scope.html. In the directive, this html is inserted into the DOM through ng-bind-html.
The html (jade) looks as follows:
#search(ng-controller="SearchController" search-directive)
It basically works. But inside this html that is included, i have some transclusive content, like {{searchType}} that i want to be resolved. Unfortunatly, that is not the case, it shows "{{searchType}}" in the browser. What can i change to make the transclusion work?
I read about $compile and $transclude, but i don't know how to use it or if it can help me solve my issue. thx!
with the help of Patrick, i was able to solve it. i changed my controller to
app.controller('SearchController', ['$scope', '$http', '$interpolate',
function($scope, $http, $interpolate) {
$scope.searchString = '';
$scope.searchType = 'Artist';
$scope.updateHtml = function() {
$http.get('/search', {
params: {
searchString: $scope.searchString,
searchType: $scope.searchType
}
}).success(function(data) {
$scope.html = $interpolate(data)($scope); // <<-- difference here
}).error(function(err){
$scope.html = err;
});
};
$scope.updateHtml();
}]);
and now my html is interpolated based on the passed-in scope. thank you!
edit:
$interpolate is only for rendering the DOM and parsing it through the scope. it simply returns plain html. if you need to actually retrieve a full working html template, with angular code in it, use $compile. i found this answer extremely helpful in sorting out the differences between $interpolate, $compile and $parse.

Updating $scope for ng-repeat after service

I have seperated out my controllers & services into modules, and on a form submit, I am trying to get data from a service and then set it in the scope, but I'm having trouble getting the view to update with the new data. I have gone through other questions with similar problems but I can't seem to get it working. The view updates fine from the Search.get() function, but not from the $scope.submitFilterForm function.
I'm trying to update like this:
$scope.searchDetails = results;
This is my code at the moment:
SearchCtrl.js
angular.module('SearchCtrl', []).controller('SearchController', function($scope, $http, Page, Search) {
$scope.pageClass = 'page-search';
$scope.showContent = false;
$scope.searchDetails = [];
Search.get().success(function(searchResults) {
$scope.searchDetails = searchResults;
Page.setTitle('Search');
$scope.showContent = true;
});
$scope.submitFilterForm = function(isValid) {
if (isValid) {
Search.filterByPostcode($scope.postcode, $scope.searchradius).success(function(results) {
console.log('results', results);
$scope.searchDetails = results;
});
}
}
});
SearchService.js
angular.module('SearchService', []).factory('Search', ['$http', function($http) {
return {
get: function() {
return $http.get('/api/places');
},
filterByPostcode: function(postcode, searchradius) {
return $http.get('/api/filter-by-postcode/'+postcode+'/'+searchradius);
}
}
}]);
search.html
<div class="places-list" ng-show="showContent">
<div class="places-list-item" ng-repeat="place in searchDetails">
{{place.place_name}}
</div>
</div>
I also have the template above set up in appRoutes.js like so:
$routeProvider
// home page
.when('/search', {
title: 'Search',
templateUrl: '/partials/search.html',
controller: 'SearchController'
})
$locationProvider.html5Mode(true);
Thanks for any help.

Can not inject a factory in a controller angular JS

I am new to angulerJS. i have defined a factory to get data from API but when i try to put the factory in a controller i got error.
That is the factory code.
(Function () {
var CategoriesFactory = function($http) {
var factory = {};
factory.getCategorys = function(account_id){
return $http.get('http://localhost:18678/api/Transaction?account_id=2');
};
factory.getTransaction = function(acc_id){
return $http.get('http://localhost:18678/api/Transaction?acc_id=2');
};
factory.getTransactionInCategory = function(category_id, from_date, to_date){
return.$http.get('http://localhost:18678/api/transaction?category='+category_id+'&account=2&from=2015-01- 01&to=2015-12-30');
};
return factory;
};
angular.module('AccApp').factory('CategoriesFactory', CategoriesFactory);
}());
here is the controller.
app.controller('CategoriesController',
function ($scope, $routeParams, $http, CategoriesFactory) {
})
and here is the error.
Unknown provider: CategoriesFactoryProvider <- CategoriesFactory
I guess you must have forgot to inject AccApp into your mai module where you have defined your app.
angular.module("app", ['AccApp']);
Please do something like this.
Hope this helps!
Why are you trying to write angular code in a wierd way ?
The goal of angular is the simplicity
var app = angular.module('AccApp',[]);
app.factory('CategoriesFactory',function($http){// you can cut and paste this factory into a seperate file if you wish
return{
getCategorys:function(account_id){
return $http.get('http://localhost:18678/api/Transaction?account_id=2');
},
getTransaction:function(acc_id){
return $http.get('http://localhost:18678/api/Transaction?acc_id=2');
},
getTransactionInCategory : function(category_id, from_date, to_date){
return.$http.get('http://localhost:18678/api/transaction?category='+category_id+'&account=2&from=2015-01- 01&to=2015-12-30');
};
}
});
Now you can Inject this factory into your controller simply:
app.controller('CategoriesController',function ($scope, $routeParams, $http, CategoriesFactory){
console.log(CategoriesFactory.getCategorys(getCategorys));
});

Categories