Complete Angular newbie here. I have the app hosted here https://bitbucket.org/builtbyvern/ultimate-angularjs-course/src and have been following along on a tutorial. It had me refactor the app using controllerAs.
The app does seem to work until I hit the ng-repeat. No errors are returned... just a commented out ng-repeat:
<!-- ngRepeat: classified in vm.classifieds -->
Code as follows but feel free to look at the bitbucket link.
<md-card flex="30" ng-repeat="classified in vm.classifieds | filter:classifiedsFilter | filter:category" class="classified">
...
<md-card>
Controller:
(function(){
"use strict";
angular
.module('ngClassifieds')
.controller('classifiedsCtrl', function($scope, $http, classifiedsFactory, $mdSidenav, $mdToast, $mdDialog, $stateParams) {
// vm for view model
var vm = this;
vm.openSidebar = openSidebar;
vm.closeSidebar = closeSidebar;
vm.saveClassified = saveClassified;
vm.editClassified = editClassified;
vm.saveEdit = saveEdit;
vm.deleteClassified = deleteClassified;
vm.classifieds;
vm.categories;
vm.editing;
vm.classified;
classifiedsFactory.getClassifieds().then(function(classifieds) {
vm.classifieds = classifieds.data;
vm.categories = getCategories(vm.classifieds);
});
var contact = {
name: "Vern",
phone: '208.283.6343',
email: 'vernworldwide#gmail.com'
}
function openSidebar() {
$mdSidenav('left').open();
}
function closeSidebar() {
$mdSidenav('left').close();
}
function saveClassified(classified) {
if (classified) {
classified.contact = contact;
vm.classifieds.push(classified);
vm.classified = {};
vm.closeSidebar();
showToast('Classified Saved!');
}
}
function editClassified(classified) {
vm.editing = true;
openSidebar();
vm.classified = classified;
}
function saveEdit(classified) {
vm.editing = false;
vm.classified = {};
closeSidebar();
showToast("Edit Saved!");
}
function deleteClassified(event, classified) {
var confirm = $mdDialog.confirm()
.title('Are your sure you want to delete ' + classified.title + '?')
.ok("Yep")
.cancel('Nope').
targetEvent(event);
$mdDialog.show(confirm).then(function(){
var index = vm.classifieds.indexOf(classified);
vm.classifieds.splice(index, 1);
}, function(){
});
}
function showToast(message){
$mdToast.show(
$mdToast.simple()
.content(message)
.position('top, right')
.hideDelay(3000)
);
}
function getCategories(classifieds) {
var categories = [];
angular.forEach(classifieds, function(item) {
angular.forEach(item.categories, function(category){
categories.push(category);
});
});
return _.uniq(categories);
}
});
})();
and of course the config
angular
.module("ngClassifieds",['ngMaterial', 'ui.router'])
.config(function($mdThemingProvider, $stateProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('teal')
.accentPalette('orange');
$stateProvider
.state('classifieds', {
url: '/classifieds',
templateUrl: 'components/classifieds/classifieds.tpl.html',
controllerAs: 'classifiedsCtrl as vm'
});
});
Related
We have a code like this which was working well before. But started to fail post version upgrade from angular 1.6 to 1.8.
Looks like it needs some changes in source code but unable to identify the spot. This is happening due to the version upgrade.
Please help me to fix this unit tests. All our tests are failing.
(function (angular, moment, TimeShift) {
'use strict';
describe('references', function() {
var NORMAL_MAIL = {
'projectId': 1234
};
var BIM_UI_INTEGRATION = {
bimModuleKey: "BIM"
};
function setCurrentTime(zoneOffset, dateUTC) {
TimeShift.setTimezoneOffset(zoneOffset);
TimeShift.setTime(new Date(dateUTC).getTime());
}
beforeEach(module('directiveModule'));
beforeEach(function() {
window.Date = TimeShift.Date;
test.mocks.registeri18nFilter();
});
afterEach(function () {
window.Date = TimeShift.OriginalDate;
});
beforeEach(inject(function($rootScope, $compile) {
this.$rootScope = $rootScope;
this.$compile = $compile;
}));
beforeEach(function() {
setCurrentTime(-660, 0);
var element = angular.element('<references></references>');
this.element = this.$compile(element)(this.$rootScope.$new());
});
describe('no model references', function() {
it('should not display anything', function() {
this.$rootScope.mail = NORMAL_MAIL;
this.$rootScope.bimUiIntegration = BIM_UI_INTEGRATION;
this.$rootScope.isPreviewingFromEditMail = false;
this.$rootScope.$digest();
expect(this.element.find('header').length).toBe(0);
});
});
});
})(window.angular, window.moment, window.TimeShift);
And our source code is here.
(function(angular) {
angular
.module('directiveModule')
.component('references', {
templateUrl: 'mail/view/directives/mailModelsReferences/references.tpl.html',
controller: referencesController,
controllerAs: 'vm',
bindings: {
mail: '<',
bimUiIntegration: '<',
isPreviewingFromEditMail: '='
}
});
ReferencesController.$inject = ['$filter'];
function ReferencesController($filter) {
const vm = this;
let i18n = $filter('i18n');
vm.hasModelReferences = hasModelReferences;
vm.toDateString = toDateString;
vm.getBimModuleName = getBimModuleName;
if (hasModelReferences()) {
vm.model = vm.mail.models.model;
vm.viewpoint = vm.mail.models.viewpoint;
}
function hasModelReferences() {
let models = vm.mail ? vm.mail.models : vm.mail;
return models && (models.model || models.viewpoint);
}
function toDateString(dateField) {
if (dateField && dateField.value) {
let fieldValue = dateField.value;
let momentVal;
if (angular.isArray(fieldValue)) {
momentVal = window.moment(`${fieldValue[0]}-${fieldValue[1]}-${fieldValue[2]}`, 'YYYY-M-D');
} else {
momentVal = window.moment(fieldValue);
}
if (momentVal && momentVal.isValid()) {
return momentVal.format('LL');
}
}
return "";
}
function getBimModuleName() {
return i18n(vm.bimUiIntegration.bimModuleKey);
}
}
})(window.angular);
Pseudo code for angular 1.5 component with RxJs:
component('demo', {
template: `<div>
<div ng-if="verificationFailed">Sorry, failed to verify</div>
<button ng-if="continueEnabled">Continue</button>
<button ng-click="verify()">Verify</button>
</div>`,
controllerAs: 'ctrl',
bindings: {
someOptions: '='
},
controller: ($scope, someService) => {
var ctrl = this;
ctrl.continueEnabled = false;
ctrl.verificationFailed = false;
ctrl.verify = function() {
Rx
.Observable
.interval(10 * 1000)
.timeout(2 * 60 * 1000)
.flatMapLatest(_ => { someService.verify(ctrl.someOptions.id)})
.retry(1)
.filter((result) => { result.completed })
.take(1)
.subscribe(_ => {
$scope.$evalAsync(_ => {
ctrl.continueEnabled = true
});
}, _ => {
$scope.$evalAsync(() => {
ctrl.verificationFailed = true;
});
});
};
}
});
Any way to avoid using $scope with $evalAsync to trigger digest? Without it the view is simply not updating.
Why? Because there is no $scope on angular2 and i want to make migration as easy as it is possible
You can use angular1-async-filter. Take a look at this good article:
http://cvuorinen.net/2016/05/using-rxjs-observables-with-angularjs-1/
Here is an example:
(function(angular) {
var myComponent = (function () {
function myComponent() {
this.template = "<div><br/> Time: {{ctrl.time | async:this}}</div>";
this.controllerAs = 'ctrl';
this.controller = "myController";
}
return myComponent;
}());
var myController = (function() {
function myController() {
this.time = Rx.Observable.interval(1000).take(50);
}
return myController;
}());
angular.module('myApp', ['asyncFilter']);
angular.module('myApp').component('myComponent', new myComponent());
angular.module('myApp').controller('myController', myController);
})(window.angular);
See it working on Plunker:
https://plnkr.co/edit/80S3AG?p=preview
This is the scenario :
<export-team>
<ul>
<li>
<button buy-ticket="{{data}}" buy-callback="onBuyTicket()">buy</button>
</li>
<li>
<button buy-ticket="{{data}}" buy-callback="onBuyTicket()">buy</button>
</li>
</ul>
</export-team>
The buyTicket directive
(function() {
'use strict';
angular
.module('myApp')
.directive('buyTicket', buyTicket);
/** #ngInject */
function buyTicket($parse, ngDialog, authService, APPCONFIG, $rootScope, shareToken, contestsFactory, shareCurrentTicket, shareIdSession, shareSessionAAMS, $location) {
var vm = this;
var directive = {
restrict: 'A',
link : function(scope, element, attributes) {
var buyCompatible = attributes['buyCompatible'];
function addZero(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
var buyTicket = function(contest) {
var d = new Date();
var y = d.getFullYear();
var m = addZero(d.getMonth()+1);
var day = addZero(d.getDate());
var h = addZero(d.getHours());
var min = addZero(d.getMinutes());
var s = addZero(d.getSeconds());
var date = ''+y+m+day+h+min+s+'';
var transactionId = $rootScope.TRANSACTIONID;
var currentTOKEN = shareToken.get();
var data = {
idSessione:currentTOKEN, // ->TOKEN
userAgent:navigator.userAgent,
sessioneAAMS:contest.aams_session_id,
gameId:APPCONFIG.GAME_ID,
transactionId:transactionId,
dateTime:date,
buyIn:contest.buy_in
}
var dialogLoading = ngDialog.open({
closeByDocument : false,
closeByEscape : false,
showClose : false,
id : 'ft-modal-loading',
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/loading.html';
$scope.title = 'Acquisto Ticket';
$scope.error = 'Il sistema sta procedendo all\'acquisto del ticket';
}]
});
contestsFactory.buyTicket(data).success(function(response){
dialogLoading.close();
if (response.esito == "0") {
if (!buyCompatible) {
shareCurrentTicket.set(response.ticketSogei);
shareSessionAAMS.set(contest.aams_session_id);
shareIdSession.set(contest.id_session);
$location.path('my-contests/'+contest.id_contest+'/'+contest.contest_status);
}
} else {
var message = response.descrizione;
var ids = ngDialog.getOpenDialogs();
var dialogError = ngDialog.open({
id : "ft-modal-error-2",
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/error.html';
$scope.title = 'Errore';
$scope.error = message;
}]
});
}
})
.error(function(){
var dialogErrorNotEndled = ngDialog.close('ft-modal-loading');
ngDialog.open({
id : 'ft-modal-error',
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/error.html';
$scope.title = 'Errore';
$scope.error = 'Il servizio non รจ attualmente disponibile';
}]
});
})
}
var openConfirmBuyTicket = function(contest) {
contest = JSON.parse(contest);
if (ngDialog.isOpen('ft-modal-contest-detail')) {
ngDialog.close('ft-modal-contest-detail');
};
if (!authService.isLogged()) {
ngDialog.open({
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/not_logged.html';
$scope.title = 'Spiacenti';
$scope.error = 'Devi essere loggato per poter partecipare ad un contest';
}]
});
} else {
ngDialog.openConfirm({
controller: ['$scope', function($scope){
$scope.title = 'CONFERMA';
$scope.bodyUrl = 'app/components/modals/body/confirm_buy.html';
$scope.contest_name = contest.name_contest;
$scope.buy_in = contest.buy_in;
$scope.currency = APPCONFIG.CURRENCY_SYMBOL;
}],
}).then(function (confirm) {
buyTicket(contest);
}, function(reject) {
});
}
}
element.on('click', function(e){
var contest = attributes['buyTicket'];
openConfirmBuyTicket(contest);
})
}
};
return directive;
}
})();
The export directive
(function() {
'use strict';
angular
.module('myApp')
.directive('exportTeam', exportTeam);
/** #ngInject */
function exportTeam(contestsFactory, ngDialog, APPCONFIG, formatDateFactory) {
var vm = this;
var directive = {
restrict: 'AE',
transclude: true,
controller : function($scope) {
$scope.test = function() {
alert('hey');
}
},
link : function(scope, element, attributes) {
element.on('click', function(e){
var ticket = attributes['exportTeam'];
var id_session = attributes['idsession'];
scope.openExportTeamDialog(ticket, id_session, false);
})
scope.openExportTeamDialog = function(ticket, aams_session_id, afterSave) {
ngDialog.open({
id : 'ft-modal-exportTeam-detail',
className : 'ngdialog ngdialog-theme-default ft-dialog-exportTeam',
controller: ['$scope', 'contestsFactory', 'APPCONFIG', function($scope, contestsFactory, APPCONFIG){
$scope.title = "Aggiungi contest compatibili";
$scope.bodyUrl = 'app/components/modals/body/exportTeam.html';
$scope.contentLoading = true;
$scope.currency = APPCONFIG.CURRENCY_SYMBOL;
$scope.afterSave = afterSave;
$scope.CompatibleContests = [];
contestsFactory.getCompatibleContests(ticket).then(function(response){
angular.forEach(response.data[0], function(item, i){
var multientryOptions = [];
if(item.multientry > 1) {
item.isMultientry = false;
var n = parseInt(item.multientry);
for (i = 1; i <= n; i++) {
multientryOptions.push({
text : i+" team",
value : i
})
}
item.multientryOptions = multientryOptions;
item.multientryOptionSelected = multientryOptions[0];
}else{
item.isMultientry = true;
};
})
$scope.CompatibleContests = response.data[0];
$scope.contentLoading = false;
})
}]
});
}
scope.openExportTeamDialog('N3E94100A725F9QG', 'M3E921013C6DCFCT', false);
}
};
return directive;
}
})();
The buy-ticket directive makes an http call, on the response i want to be able to call the onBuyTicket method of the <export> directive.
I'm trying to understand the best way to do that.
Thanks everyone
This sample show to you how can call an function from your directive
In this sample you can see we just insert data in our directive, and then we handle the data and other action in the directive.
var app = angular.module("app", []);
app.controller("ctrl", function ($scope) {
$scope.dataFromYourController = [
{ name: "Concert Jennifer", value: 200 },
{ name: "007", value: 100 }
];
})
.directive("export", function () {
var template = "<div>" +
"<ul>" +
"<li ng-repeat=\"array in arrays\">" +
"<button ng-click=\"onBuyTicket()\">buy Ticket {{array.name}}</button><hr>" +
"</li>" +
"</ul>" +
"</div>";
return {
restrict: "E",
template: template,
scope: {
data: "="
},
link: function (scope, elem, attrs, ngModel) {
scope.arrays = scope.data;
scope.onBuyTicket = function () {
alert("calling function from directive");
}
}
};
})
<!doctype html>
<html ng-app="app" ng-controller="ctrl">
<head>
</head>
<body>
<h1>call action from your directive</h1>
<export data="dataFromYourController"></export>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>
#eesdil
var directive = {
restrict: 'AE',
transclude: true,
controller : function($scope) {
$scope.onBuyTicket = function() {
alert('hey');
}
}
}
Ho can I call that from the buy-ticket directive ?
Use the $parent
<button buy-ticket="{{data}}" buy-callback="$parent.onBuyTicket()">buy</button>
So the expor directive something like:
var directive = {
restrict: 'AE',
template: '<ng-tansclude></ng-transclude>',
transclude: true,
controller : function($scope) {
$scope.onBuyTicket = function() {
alert('hey');
}
}
}
UPDATED:
see the plunker:
https://plnkr.co/edit/fmyJ4oPLvTiI0TzO7h1b?p=preview
It really depends what you can call and what you cannot based on the scopes... here if you would remove the scope from the export directive would work without the $parent also as export would share the same scope as the parent (main view)
The best way to communicate events from a child directive to a parent directive (or controller) is to use the $emit method of the scope.
What you want to do is take an ng-click event, get additional information with an $http call, and $emit an event with the additional information to be used by your parent directive (or controller).
HTML
<button buy-ticket="data" ng-click="onBuyTicket()">buy</button>
The directive:
angular.module("myApp").directive("buyTicket", function($http) {
function linkFn(scope,elem,attrs) {
scope.onBuyTicket = function() {
var buyData = scope.$eval(attrs.buyTicket);
var url = someFunction(buyData);
$http.get(url).then (function (response) {
var httpData = response.data;
scope.$emit("buyTicket.click", buyData, httpData);
});
};
};
return {
restrict: "AE",
link: linkFn
};
});
In the parent controller:
$scope.$on("buyTicket.click", function (buyData, httpData) {
console.log(buyData);
console.log(httpData);
});
Notice that I used the $eval method to get the data from the variable named by the buy-ticket attribute.
When choosing a name for the event, I recommend including the name of the directive in the event's name. It makes it clear the source of the event and is unlikely to be duplicated elsewhere.
I want to change the siteType value depending on screen width without editing in view part.
app.js
'use strict';
var app = angular.module('Location', []).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/', { templateUrl: 'pages/' + **params.siteType** + '/locationList.html', controller: Location }).
when('/locationDetail/:projectId', {
templateUrl: function (params) { return 'pages/' + **params.siteType** + '/locationDetail.html'; },
controller: Location
}).
otherwise({ redirectTo: '/' });
}])
app.config(['$locationProvider', function($location) {
$location.hashPrefix('!');
}]);
Controller.js
'use strict';
function Location($scope, $http, $routeParams) {
$scope.projectId = $routeParams.projectId;
$scope.selectedProject = null;
$scope.locationList = null;
$scope.siteType = "desktop";
$(window).resize(function(){
if(window.innerWidth < 600) {
$scope.$apply(function(){
$scope.siteType = "mobile";
});
} else {
$scope.$apply(function(){
$scope.siteType = "desktop";
});
}
});
$http.get("location.json")
.success(function(data){
$scope.locationList = data;
var indexedloc = [];
$scope.locationListToFilter = function(){
indexedloc = [];
return $scope.locationList;
}
$scope.filterLocation = function(Loc){
var locationIsNew = indexedloc.indexOf(Loc.field_data_field_location_field_location) == -1;
if(locationIsNew){
indexedloc.push(Loc.field_data_field_location_field_location);
}
return locationIsNew;
}
$scope.returnFilterLoc = function(){return indexedloc};
if($scope.projectId && $scope.projectId != null) {
for(var i = 0;i < $scope.locationList.length;i++){
if($scope.locationList[i].tid == $scope.projectId) {
$scope.selectedProject = $scope.locationList[i];
}
}
}
})
.error(function(data) {
$("div.category-wrapper").html("Error");
});
}
You can have a directive or controller that sets the value of what is included:
e.g.
<div ng-controller="MyController">
<div ng-include="{{ template }}"></div>
</div>
and on your controller you can set the value of template depending on the window or document
$(window).height(); // returns height of browser viewport
$(document).height(); // returns height of HTML document
$(window).width(); // returns width of browser viewport
$(document).width(); // returns width of HTML document
e.g.
myApp.controller('MyController', ['$scope', function($scope) {
if($(window).width() < 1199)
$scope.template = "mytemplate1.html"
else
$scope.template = "mytemplate2.html"
}]);
But all the above is a messy, not safe, ugly solution. You should handle the responsiveness using CSS media-queries.
I'm wondering what could be a good way to share directive
between controller.
I've got ie two directives to use in different controller
with different configuration the first think I thought of
using like:
//html
<body data-ng-controller="MainCtrl">
<div class="container">
<div data-ui-view></div>
</div>
</body>
//js
.controller('MainCtrl', function ($scope,$upload) {
/*File upload config*/
$scope.onFileSelect = function($files) {
for (var i = 0; i < $files.length; i++) {
var file = $files[i];
$scope.upload = $upload.upload({
url: 'server/upload/url',
method: 'POST',
data: {myObj: $scope.myModelObj},
file: file,
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
console.log(data);
});
}
};
/* Datepicker config */
$scope.showWeeks = true;
$scope.minDate = new Date();
$scope.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};
$scope.dateOptions = {
'year-format': "'yy'",
'starting-day': 1
};
$scope.format = 'MMM d, yyyy';
})
.controller('IndexCtrl', function ($scope) {
})
doing so I can use all the functions in my children controller
but I don't like very much because of collision problems.
Since you cannot use a service (you can't use $scope in a service) the other alternatives could be make an other directive or put the code in a run block
but it's quite the same using a parent controller so
what do you think about ?
UPDATE
what do you think about this approach ?
//outside of angular stauff
function MyTest(){
this.testScope = function(){
console.log('It works');
}
}
//inside a controller
$scope.ns = new MyTest();
//in the view
<p ng-click="ns.testScope()">ppp</p>
RIUPDATE
this seems the best option :)
MyTest.call($scope);
Consider the method described by this post: Extending AngularJS Controllers Using the Mixin Pattern
Instead of copying your methods out of a service, create a base controller that contains those methods, and then call extend on your derived controllers to mix them in. The example from the post:
function AnimalController($scope, vocalization, color, runSpeed) {
var _this = this;
// Mixin instance properties.
this.vocalization = vocalization;
this.runSpeed = runSpeed;
// Mixin instance methods.
this.vocalize = function () {
console.log(this.vocalization);
};
// Mixin scope properties.
$scope.color = color;
// Mixin scope methods.
$scope.run = function(){
console.log("run speed: " + _this.runSpeed );
};
}
Now we can mixin AnimalController into DogController:
function DogController($scope) {
var _this = this;
// Mixin Animal functionality into Dog.
angular.extend(this, new AnimalController($scope, 'BARK BARK!', 'solid black', '35mph'));
$scope.bark = function () {
_this.vocalize(); // inherited from mixin.
}
}
And then use DogController in our template:
<section ng-controller="DogController">
<p>Dog</p>
<!-- Scope property mixin, displays: 'color: solid black' -->
<p ng-bind-template="color: {{ color }}"></p>
<!-- Calls an instance method mixin, outputs: 'BARK BARK!' -->
<button class="btn" ng-click="bark()">Bark Dog</button>
<!-- Scope method mixin, outputs: 'run speed: 35mph' -->
<button class="btn" ng-click="run()">Run Dog</button>
</section>
The controllers in this example are all in the global space and are included in the markup as follows.
<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="lib/angular.js"></script>
<script type="text/javascript" src="app/controllers/animal-controller.js"></script>
<script type="text/javascript" src="app/controllers/dog-controller.js"></script>
<script type="text/javascript" src="app/controllers/cat-controller.js"></script>
<script type="text/javascript" src="app/app.js"></script>
I haven't tested it, but I don't see why the following wouldn't work:
var myApp = angular.module('myApp', [])
.controller('AnimalController', ['$scope', 'vocalization', 'color', 'runSpeed', function ($scope, vocalization, color, runSpeed) { /* controller code here */}]);
.controller('DogController', ['$scope', '$controller', function($scope, $controller) {
var _this = this;
// Mixin Animal functionality into Dog.
angular.extend(this, $controller('AnimalController', {
$scope: scope,
vocalization: 'BARK BARK!',
color: 'solid black',
runSpeed:'35mph'
}));
$scope.bark = function () {
_this.vocalize(); // inherited from mixin.
}
}]);
see: docs for $controller service
What you want is terrible.
You wouldn't want your controllers to know anything about each other, let alone, one having access to the function of the other. You can just use a Service to achieve that. As for using directives, not sure what exactly you want to happen.
As for your second thing, you can as easily do this
.service('MyTestService', function(){
return {
testScope: function(){
console.log('It works');
}
};
})
.controller('MyController', ['$scope', 'MyTestService', function($scope, MyTestService){
$scope.testScope = MyTestService.testScope;
}])
and in your view:
<p ng-click="testScope()">ppp</p>
I ended up with:
//service
.service('PostUploader',function($upload){
var that = this;
var fileReaderSupported = window.FileReader !== null;
this.notify = null;
this.success = null;
this.showAlert = false;
this.avatar = '';
this.onFileSelect = function($files) {
var $file = $files[0];
var filename = $file.name;
this.avatar = filename;
var isImage = /\.(jpeg|jpg|gif|png)$/i.test(filename);
if(!isImage){
this.showAlert = true;
return;
}
this.showAlert = false;
if (fileReaderSupported && $file.type.indexOf('image') > -1) {
var fileReader = new FileReader();
fileReader.readAsDataURL($file);
fileReader.onload = that.notify;
}
$upload.upload({
url :'/api/post/upload',
method: 'POST',
headers: {'x-ng-file-upload': 'nodeblog'},
data :null,
file: $file,
fileFormDataName: 'avatar'
})
.success(that.success)
.progress(function(evt) {
})
.error(function(data, status, headers, config) {
throw new Error('Upload error status: '+status);
})
};
this.closeAlert = function() {
this.showAlert = false;
};
})
//controller
/* Uploader post */
$scope.dataUrl = null;
$scope.avatar = PostUploader.avatar;
$scope.showAlert = PostUploader.showAlert;
$scope.onFileSelect = PostUploader.onFileSelect;
$scope.closeAlert = PostUploader.closeAlert;
PostUploader.notify = function(e){
$timeout(function() {
$scope.dataUrl = e.target.result;
});
};
PostUploader.success = function(data, status, headers, config) {
$timeout(function() {
$scope.post.avatar = data.url;
});
}
$scope.$watch('avatar',function(newVal, oldVal){
if(newVal) {
$scope.avatar = newVal;
}
});
$scope.$watch('showAlert',function(newVal, oldVal){
$scope.showAlert = newVal;
$scope.dataUrl = null;
});
I did so because I've to do the same thing in create post and edit post but all in all
I've got quite the same repeated code ! :)
The only good thing is the code has got less logic.
obvious but brilliant solution (may be)
(function(window, angular, undefined) {
'use strict';
angular.module('ctrl.parent', [])
.run(function ($rootScope) {
$rootScope.test = 'My test'
$rootScope.myTest = function(){
alert('It works');
}
});
})(window, angular);
angular.module('app',['ctrl.parent'])
.controller('ChildCtrl', function($scope){
});
It's easy and clean and don't see any drawback(it's not global)
UPDATE
'use strict';
(function(window, angular, undefined) {
'use strict';
angular.module('ctrl.parent', [])
.controller('ParentController',function (scope) {
scope.vocalization = '';
scope.vocalize = function () {
console.log(scope.vocalization);
};
});
})(window, angular);
angular.module('app',['ctrl.parent'])
.controller('ChildCtrl', function($scope,$controller){
angular.extend($scope, new $controller('ParentController', {scope:$scope}));
$scope.vocalization = 'CIP CIP';
});
just a little neater and it works CIP CIP :)