I am still learning angular and got this Problem:
Service Definition:
app.service('headService', function($window) {
this.display = 0;
return {
setTitle: function (newTitle) { $window.document.title = newTitle; },
setDisplay: function (value) { this.display = value;},
getDisplay: function () {
if(this.display===undefined){
this.display = 1;
}
return this.display
}
};
})
Controller Definition:
app.controller('startController', function(headService) {
headService.setTitle('by app 3');
this.isVisible = function () {
if(headService.getDisplay()===1){
return true;
} else {
return false;
}
}
});
directive implementation
app.directive("startDirective", function(headService) {
return {
restrict : "E",
templateUrl: 'app/templates/start.html',
controller: 'startController'
};
});
Now I would like to Show if the method this.isVisible Returns true
<div layout="column" flex>
<start-directive></start-directive>
<content-directive></content-directive>
<login-directive></login-directive>
</div>
which is included by
<body ng-controller="bodyController">
<application-directive layout="row" flex></application-directive>
</body>
But I can't get it running. Any hint?
Related
I'm new to angularJS, and now I'm trying to realize some parts.
The questions is: how do I get access to callback onFinish() which is passed to component "my-timer" and run it? this.onFinish() returns the error.
Here is my markup:
<div ng-app="app" ng-controller="MyCtrl as myCtrl">
<div>
Status: {{myCtrl.status ? myCtrl.status : 'Waiting...'}}
</div>
<div>
<button ng-click="myCtrl.addTimer(5)">Add timer</button>
</div>
<div ng-repeat="timer in myCtrl.timers">
<div>
<h3>Timer {{timer.id}}</h3>
<button ng-click="myCtrl.removeTimer($index)">X</button>
<my-timer id="{{timer.id}}" start-seconds="{{timer.seconds}}" on-finish="myCtrl.onFinish(endTime)"></my-timer>
</div>
</div>
</div>
And here is index.js
var app = angular.module('app', []);
app.controller('MyCtrl', class {
constructor($scope) {
this.status = null;
this.timerId = 0;
this.timers = [];
this.addTimer(10);
this.addTimer(3);
console.log($scope);
}
addTimer(seconds) {
this.timers.push({
id: this.timerId++,
seconds
});
}
removeTimer(index) {
this.timers.splice(index, 1);
}
onFinish(endTime){
this.status = `Timer finished at ${endTime}`;
console.log(endTime);
}
});
app.component('myTimer', {
bindings: {
id: '#',
startSeconds: '#',
onFinish: '&',
},
controller: function($interval, $scope) {
this.endTime = null;
this.$onInit = function() {
this.countDown();
};
this.countDown = function() {
$interval(() => {
this.startSeconds = ((this.startSeconds - 0.1) > 0) ? (this.startSeconds - 0.1).toFixed(2) : 0;
}, 100);
};
},
template: `<span>{{$ctrl.startSeconds}}</span>`,
});
And here is jsFiddle
this.$onInit = function() {
this.countDown();
};
this.onFinish('1');
The problem here is that you tried to execute this.onFinish right in controller's body. And that wont work that way. If you want this function to be called during initialization, move it to $onInit
this.$onInit = function() {
this.countDown();
this.onFinish('1');
};
Otherwise, call it from another component method. You can only declare variables and component methods in controller body, but not call functions.
I'm trying to popup a modal on onChange event of a formly custom checkbox. Modal turnup okay, but can't make the buttons working :(. Where I'm doing wrong?
{
key: 'coordinatesToLocateSite',
className: 'col-sm-8 col-md-8 col-lg-8',
type: 'custom_checkbox',
templateOptions: {
label: 'Use coordinates to locate site',
onChange: function($viewValue, $modelValue, scope) {
if ($viewValue === true) {
scope.modalInstance = scope.$uibModal.open({
animation: true,
templateUrl: 'address_replace_coordinates_check.html'
})
}
function check() {
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
scope.uncheck = function uncheck(keyName) {
$scope.model[keyName] = !$scope.model[keyName];
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
}
},
expressionProperties: {
'templateOptions.disabled': 'formState.disabled'
}
}
In the template my button are as follows,
<div class="modal-footer">
<button class="btn btn-warning" type="button" ng-click="check()">Ok</button>
<button class="btn btn-primary" type="button" ng-click="uncheck('coordinatesToLocateSite')">Cancel</button>
</div>
And lastly, I've tried the following as well.
formlyConfigProvider.setType({
name: 'custom_checkbox',
templateUrl: 'bcsa_checkbox.html',
wrapper: ['bootstrapHasError'],
apiCheck: function apiCheck(check) {
return {
templateOptions: {
onChange: check.oneOfType([check.string, check.func]),
label: check.string
}
};
},
controller: /* #ngInject */ function($scope, $sce, $uibModal) {
'ngInject';
$scope.$uibModal = $uibModal;
var markerOfRequired = '<span class="red"> \n<strong> \n* \n</strong> \n</span>';
$scope.labelDisplay = $sce.trustAsHtml($scope.to.label + ($scope.to.required ? markerOfRequired : ''));
$scope.onChange = onChange;
$scope.check = check;
$scope.uncheck = uncheck;
function onChange($event) {
if (angular.isString($scope.to.onChange)) {
return $scope.$eval($scope.to.onChange, { $event: $event, $scope: $scope });
} else {
return $scope.to.onChange($event, $scope);
}
}
function check() {
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
function uncheck(keyName) {
$scope.model[keyName] = !$scope.model[keyName];
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
}
});
i couldn't make a fiddle to test on but reading your code i see you'r not calling the functions correctly, the ng-click should access an object defined inside the $scope
so try changing the functions declarations to this
$scope.onChange = function ($event) {
if (angular.isString($scope.to.onChange)) {
return $scope.$eval($scope.to.onChange, { $event: $event, $scope: $scope });
} else {
return $scope.to.onChange($event, $scope);
}
}
$scope.check = function () {
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
$scope.uncheck = function (keyName) {
$scope.model[keyName] = !$scope.model[keyName];
if (scope.modalInstance) {
scope.modalInstance.close();
}
}
I figure it out, when we open the $uibModal we should pass the scope along with that. So, I've modified some codes.
scope.modalInstance = scope.$uibModal.open({
animation: true,
backdrop: false,
keyboard: false,
scope: scope,
templateUrl: 'address_replace_coordinates_check.html'
})
In the controller, instead of accessing scope I've accessed its $parent.
$scope.check = check;
$scope.uncheck = uncheck;
function check() {
let modalInstance = this.$parent.modalInstance;
if (modalInstance) {
modalInstance.close();
}
}
function uncheck(keyName) {
let scope = this.$parent;
let modalInstance = scope.modalInstance;
scope.model[keyName] = !scope.model[keyName];
if (modalInstance) {
modalInstance.close();
}
}
UPDATE
The service seem to be fetching data but when the data is sent to controller, it is undefined. Adding the service.js file for reference as well
service.js
.service('VideosModel', function ($http, Backand) {
var service = this,
baseUrl = '/1/objects/',
objectName = 'videos/';
function getUrl() {
return Backand.getApiUrl() + baseUrl + objectName;
}
function getUrlForId(id) {
return getUrl() + id;
}
service.all = function () {
console.log($http.get(getUrl()));
return $http.get(getUrl());
};
service.fetch = function (id) {
console.log('Inside s');
console.log($http.get(getUrlForId(id)));
return $http.get(getUrlForId(id));
};
service.create = function (object) {
return $http.post(getUrl(), object);
};
service.update = function (id, object) {
return $http.put(getUrlForId(id), object);
};
service.delete = function (id) {
return $http.delete(getUrlForId(id));
};
})
Pic
I am trying to implement the master-detail view on one of the tabs in my app using this instead of scope (example using scope here). But my details view is not getting the data/ it is saying undefined for detailsCtrl. I believe I'm making a mistake in my controller or app.js but I don't really have an idea about how to fix it.
master.html
<ion-view view-title="Videos">
<div ng-if="!vm.isCreating && !vm.isEditing">
<ion-content class="padding has-header">
<!-- LIST -->
<div class="row gallery">
<div class="list card col col-25" ng-repeat="object in vm.data"
ng-class="{'active':vm.isCurrent(object.id)}">
<a class="cardclick" href="#/details/{{object.id}}">
<div class="item item-image">
<img ng-src="{{object.img}}"/>
</div>
<div class="item item-icon-left assertive">
<i class="icon ion-play"></i>
<p> Watch</p>
<h2> {{object.title}} </h2>
</div>
</a>
</div>
</div>
</ion-content>
</div>
details view or videoplayer.html
<ion-view title="Now Playing" hide-nav-bar="true">
<div class="modal transparent fullscreen-player">
<video src="{{object.src}}" class="centerme" controls="controls" autoplay></video>
</div>
app.js
$stateProvider
// setup an abstract state for the tabs directive
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginCtrl as login'
})
.state('forgotpassword', {
url: '/forgot-password',
templateUrl: 'templates/forgot-password.html',
})
.state('tab', {
url: '/tabs',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('tab.videos', {
url: '/videos',
views: {
'tab-videos': {
templateUrl: 'templates/tab-videos.html',
controller: 'VideosCtrl as vm'
}
}
})
.state('tab.games', {
url: '/games',
views: {
'tab-games': {
templateUrl: 'templates/tab-games.html'
}
}
})
.state('tab.help', {
url: '/help',
views: {
'tab-help': {
templateUrl: 'templates/tab-help.html'
}
}
})
.state('details', {
url: "/details/:id",
templateUrl: 'templates/videoplayer.html',
controller: 'detailsCtrl as vm'
});
$urlRouterProvider.otherwise('/login');
$httpProvider.interceptors.push('APIInterceptor');
})
controller
.controller('VideosCtrl', function (VideosModel, $rootScope) {
var vm = this;
function goToBackand() {
window.location = 'http://docs.backand.com';
}
function getAll() {
vm.data=[];
VideosModel.all()
.then(function (result) {
vm.data = result.data.data;
console.log(vm.data);
});
}
function initCreateForm() {
vm.newObject = {name: '', description: ''};
}
function setEdited(object) {
vm.edited = angular.copy(object);
vm.isEditing = true;
}
function isCurrent(id) {
return vm.edited !== null && vm.edited.id === id;
}
function cancelEditing() {
vm.edited = null;
vm.isEditing = false;
}
function cancelCreate() {
initCreateForm();
vm.isCreating = false;
}
function clearData(){
vm.data = null;
}
function create(object) {
VideosModel.create(object)
.then(function (result) {
cancelCreate();
getAll();
});
}
function update(object) {
VideosModel.update(object.id, object)
.then(function (result) {
cancelEditing();
getAll();
});
}
function deleteObject(id) {
VideosModel.delete(id)
.then(function (result) {
cancelEditing();
getAll();
});
}
vm.edited = null;
vm.isEditing = false;
vm.isCreating = false;
vm.getAll = getAll;
vm.create = create;
vm.update = update;
vm.delete = deleteObject;
vm.setEdited = setEdited;
vm.isCurrent = isCurrent;
vm.cancelEditing = cancelEditing;
vm.cancelCreate = cancelCreate;
vm.goToBackand = goToBackand;
vm.isAuthorized = false;
$rootScope.$on('authorized', function () {
vm.isAuthorized = true;
getAll();
});
$rootScope.$on('logout', function () {
clearData();
});
if(!vm.isAuthorized){
$rootScope.$broadcast('logout');
}
initCreateForm();
getAll();
})
.controller('detailsCtrl',function($stateParams,VideosModel){
var vm = this;
var videoId = $stateParams.id;
function getforId(id) {
vm.data=[];
VideosModel.fetch(id)
.then(function (result) {
vm.data = result.data.data;
console.log(vm.data);
});
}
getforId(videoId);
});
How do pass the data using this?
In order to use controllerAs syntax (bind your scope properties to 'this' in the controller) you need to give your controller an alias in the html.
<div ng-controller="detailsCtrl as vm">
By default, your html is going to reference $scope on your controller unless you give it an alias.
https://docs.angularjs.org/api/ng/directive/ngController
I have this factory:
.factory('Options', function () {
var getOptions = function () {
var storageData = sessionStorage.siteOptions;
if (storageData !== 'undefined')
return angular.fromJson(storageData);
return {
rotateBackground: false,
enableMetro: true
};
};
var saveOptions = function (options) {
sessionStorage.siteOptions = angular.toJson(options);
}
return {
get: getOptions,
save: saveOptions
};
});
which works fine on my profile page:
.controller('ProfileController', ['Options', function (options) {
var self = this;
self.options = options.get();
self.save = function () {
options.save(self.options);
}
}]);
The html looks like this:
<div class="row" ng-controller="ProfileController as profile">
<div class="large-4 columns">
<h2>Site options</h2>
<form name="optionsForm" ng-submit="profile.save()" role="form">
<div class="row">
<div class="large-12 columns">
<input id="enable-metro" type="checkbox" ng-model="profile.options.enableMetro"><label for="enable-metro">Enable metro design</label>
</div>
<div class="large-12 columns">
<input id="enable-background-rotate" type="checkbox" ng-model="profile.options.rotateBackground"><label for="enable-background-rotate">Enable rotating background</label>
</div>
<div class="large-12 columns">
<button class="button">Save</button>
</div>
</div>
</form>
</div>
</div>
But I have this other page that has a controller that needs to be aware if the options are ever saved. Basically, if saveOptions is ever called, then I need any page that looks at options to be notified.
The reason for this, is for example:
.controller('MetroController', ['Options', function (options) {
scope.options = options.get();
scope.$watch(function () {
return options.get();
}, function () {
scope.options = options.get();
});
}])
// ---
// DIRECTIVES.
// ---
.directive('metro', function () {
return {
restrict: 'A',
controller: 'MetroController',
controllerAs: 'metro',
link: function (scope, element, attr) {
scope.$watch(function () {
return metro.options.enableMetro;
}, function (enableMetro) {
if (enableMetro) {
element.addClass('metro');
} else {
element.removeClass('metro');
}
});
}
}
});
As you can see, this is trying to apply a class based on the enableMetro flag. But when I run this, I get an error about the amount of iterations this has had to loop through.
Can someone help me with this?
I think I have this solved.
I changed my options factory to this:
.factory('Options', function () {
var getOptions = function () {
var storageData = sessionStorage.siteOptions;
if (storageData !== 'undefined')
return angular.fromJson(storageData);
return {
rotateBackground: false,
enableMetro: true
};
};
var saveOptions = function (options) {
sessionStorage.siteOptions = angular.toJson(options);
current = getOptions();
}
var current = getOptions();
return {
current: current,
save: saveOptions
};
});
then in my controllers, I just did this:
.controller('MetroController', ['$scope', 'Options', function ($scope, options) {
var self = this;
self.options = options.current;
$scope.$watch(function () {
return options.current;
}, function () {
self.options = options.current;
});
}])
// ---
// DIRECTIVES.
// ---
.directive('metro', function () {
return {
restrict: 'A',
controller: 'MetroController',
link: function (scope, element, attr, controller) {
scope.$watch(function () {
return controller.options.enableMetro;
}, function (enableMetro) {
if (enableMetro) {
element.addClass('metro');
} else {
element.removeClass('metro');
}
});
}
}
});
and that seems to work fine.
Using ui-bootstrap I have a really simple custom directive that lists alerts at the top of the page. On normal pages it works like a champ. When I use my directive inside a $modal popup I get "undefined is not a function" at ngRepeatAction.
The directive I have behind the modal on the main page still works. I can see it behind the modal. It's just the one in the modal popup that breaks. What am I doing wrong?
Modal open code:
$modal.open({
templateUrl: 'partials/main/servers/serverAuths/edit.html',
controller: function($scope, $modalInstance) {
$scope.auth = angular.copy(auth);
$scope.auth.password = null;
$scope.saveAuth = function() {
Auths.editAuth($scope.auth).then(
function(resp) {
if (resp.rc===0) {
Alerts.addAlert('success', 'Auth `'+$scope.auth.name+'` saved.');
_.extend(auth, $scope.auth);
$modalInstance.close();
} else {
Alerts.addAlert('danger', 'Auth `'+$scope.auth.name+'` could not be saved. ' + resp.message, 'serverAuths');
}
}
);
};
$scope.resetAuth = function() {
$modalInstance.close();
};
}
}).result.then(
function() {
Auths.getAuthList().then(
function(resp) {
$scope.auths = resp;
}
);
}
);
Directive template:
<div class="alert-wrapper alert-{{ alert.type }}"
ng-repeat="alert in alerts"
ng-class="{ 'relative':relative }">
<div class="container">
<div alert type="alert.type" close="closeAlert($index)">{{alert.msg}}</div>
</div>
</div>
Directive code:
angular.module('app')
.directive('appAlerts', function() {
return {
restrict: 'A',
replace: true,
scope: {
watchForm: '=',
relative: '#'
},
templateUrl: 'partials/directives/appAlerts.html',
controller: function($scope, Alerts) {
$scope.closeAlert = function(idx) { Alerts.closeAlert(idx); };
$scope.alerts = Alerts.getAlerts();
}
};
});
Alerts Factory:
angular.module('app').factory('Alerts', function($timeout) {
var alerts = [];
function timeoutAlert(a) {
$timeout(function() {
a.splice(0, 1);
}, 2500);
}
var addAlert = function(type, msg) {
alerts.push({type:type, msg:msg});
timeoutAlert(alerts);
};
var closeAlert = function(index) {
alerts.splice(index, 1);
};
var getAlerts = function() {
return alerts;
};
var killAlert = function(msg) {
var alert = _.where(alerts, {msg:msg});
var idx = _.indexOf(alerts, alert[0]);
if (idx > -1) {
closeAlert(idx);
}
};
return {
addAlert:addAlert,
closeAlert:closeAlert,
getAlerts:getAlerts,
killAlert:killAlert
};
});