I'm working on a angular fullstack project which uses Babel and Angular 1.5.0.
The issue is that when I'm constructing an array (this.events = []) I cannot target this array on $onInit() where I'm supposed to populate data to be displayed on ui-calendar. I do this on this.awesomeTesting = [];
So I need to populate this.events[] array with data from $http.get('/api/calendars/') inside $onInit() but I don't understand why I cannot target the array so I can populate the data.
What am I doing wrong?
Here is my code:
'use strict';
(function() {
class MainController {
constructor($http, $scope, socket, uiCalendarConfig) {
this.$http = $http;
this.socket = socket;
this.awesomeThings = [];
this.awesomeTesting = [];
this.events = [];
this.events.splice(0, this.events.length);
this.eventSources = [this.events];
console.log(this.eventSources);
/* config object */
$scope.uiConfig = {
calendar:{
height: 450,
editable: true,
header:{
left: 'month',
center: 'title',
right: 'today prev,next'
},
dayClick: $scope.alertEventOnClick,
eventDrop: $scope.alertOnDrop,
eventResize: $scope.alertOnResize
}
};
$scope.$on('$destroy', function() {
socket.unsyncUpdates('thing');
})
}
$onInit() {
this.$http.get('/api/things').then(response => {
this.awesomeThings = response.data;
this.socket.syncUpdates('thing', this.awesomeThings);
});
this.$http.get('/api/calendars').then(response => {
this.awesomeTesting = response.data;
this.awesomeTesting.forEach(function (objectItem) {
console.log('displays property in each object: ', objectItem.title);
this.events.push({
title: objectItem.title,
start: objectItem.start
});
});
this.socket.syncUpdates('calendar', this.awesomeTesting);
});
}
addThing() {
if (this.newThing) {
this.$http.post('/api/things', { name: this.newThing });
this.newThing = '';
}
}
deleteThing(thing) {
this.$http.delete('/api/things/' + thing._id);
}
}
angular.module('myApp')
.component('main', {
templateUrl: 'app/main/main.html',
controller: MainController
});
})();
I fixed the issue by making a for loop instead of .forEach() but I still would like to know the answer how it could be done with .forEach()?
The solution with for loop:
for (var i = 0; i < this.awesomeTesting.length; i++) {
this.events.push({
title: this.awesomeTesting[i].title,
start: this.awesomeTesting[i].start
});
}
Try to remove this.events.splice(0, this.events.length);
hope this helps.
Try This:
var that = this;
and than replace this.events -> that.events
`$onInit() {
*var that = this;*
this.$http.get('/api/things').then(response => {
this.awesomeThings = response.data;
this.socket.syncUpdates('thing', this.awesomeThings);
});
this.$http.get('/api/calendars').then(response => {
this.awesomeTesting = response.data;
this.awesomeTesting.forEach(function (objectItem) {
console.log('displays property in each object: ', objectItem.title);
*that.events.*push({
title: objectItem.title,
start: objectItem.start
});
});
this.socket.syncUpdates('calendar', this.awesomeTesting);
});
}`
Related
I a trying to access the browser $window object in angular but I keep getting this error Error: $window is undefined even when this same code works perfectly in a service provider code:
Here is the sessionFactory code:
angular.module('app').factory('sessionFactory', [
'$window',
'formattingFactory',
sessionFactory
]);
var myFormattingFactory = new formattingFactory();
function sessionFactory($window, formattingFactory) {
function formatText(text) {
myFormattingFactory.format(text);
}
return {
save: function(key, value) {
$window.sessionStorage.setItem(key, formatText(value));
},
get: function(key) {
return $window.sessionStorage.getItem(key);
},
clear: function() {
$window.sessionStorage.clear();
}
}
}
And this is my sessionController code:
angular.module('app').controller('sessionController', [
'sessionService',
'sessionFactory',
sessionController
]);
var mySessionFactory = new sessionFactory();
function sessionController(sessionService, sessionFactory) {
var vm = this;
vm.getFactorySession = getFactorySession;
vm.setFactorySession = setFactorySession;
vm.clearFactorySession = clearFactorySession;
vm.getServiceSession = function() {
vm.model = {
name: sessionService.get('name'),
nickname: sessionService.get('nickname'),
status: 'Retrieved by service on' + new Date()
}
}
vm.setServiceSession = function() {
sessionService.save('name', vm.model.name);
sessionService.save('nickname', vm.model.nickname);
vm.getServiceSession();
}
vm.clearServiceSession = function() {
sessionService.clear();
vm.getServiceSession();
}
function getFactorySession() {
vm.model = {
name: mySessionFactory.get('name'),
nickname: mySessionFactory.get('nickname'),
status: 'Retrieved by Factory on ' + new Date()
};
}
function setFactorySession() {
mySessionFactory.save('name', vm.model.name);
mySessionFactory.save('nickname', vm.model.nickname);
getFactorySession();
}
function clearFactorySession() {
mySessionFactory.clear();
getFactorySession();
}
}
And this is the code for the sessionService that works great and can access the browser $window object without any error:
angular.module('app').service('sessionService', [
'$window',
sessionService
]);
function sessionService($window) {
this.save = save;
this.get = get;
this.clear = clear;
function save(key, value) {
$window.sessionStorage.setItem(key, value);
}
function get(key) {
return $window.sessionStorage.getItem(key)
}
function clear() {
$window.sessionStorage.clear();
}
}
This is the formattingFactory code:
angular.module('app').factory('formattingFactory', [
formattingFactory
]);
function formattingFactory() {
function format(text) {
this.text = text;
if ((text.trim().length % 2) === 0) {
return text.toUpperCase();
} else {
return text.toLowerCase();
}
}
return {
format: format
}
}
myFormattingFactory is a dependency of sessionFactory and should reside inside its factory function:
angular.module('app').factory('sessionFactory', [
'$window',
'formattingFactory',
sessionFactory
]);
function sessionFactory($window, formattingFactory) {
// formattingFactory is an object and can be used here
...
formattingFactory service instance is passed as an argument there. It is undefined otherwise.
I have two modules "core" and "ui".
The ui module depends on core. This is the code for my core.js :
var core = angular.module('core', [ 'ngRoute' ]);
//Services
core.service('httpInformationService', function() {
this.requestCount = 0;
this.responseCount = 0;
this.incrementRequest = function() {
this.requestCount++;
console.log('incrementRequest:' + this.requestCount);
};
this.incrementReponse = function() {
this.responseCount++;
}
this.decrementRequest = function() {
this.requestCount--;
console.log('decrementRequest:' + this.requestCount);
};
this.decrementResponse = function() {
responseCount--;
}
this.getRequestCount = function() {
return requestCount;
}
this.getResponseCount = function() {
return responseCount;
}
});
//Service provider
core.provider("httpServiceInformationProvider", function() {
var provider = {};
provider.$get = ['httpInformationService', function( service ) {
return service;
}];
return provider;
});
//HTTP Interceptor
core.factory('coreHttpInterceptor' ,function( httpInformationService ){
var coreHttpInterceptor = {
request: function(config) {
httpInformationService.incrementRequest();
return config;
},
response: function(response) {
httpInformationService.decrementRequest();
return response;
}
}
return coreHttpInterceptor;
});
var config = {
base_url: enviromnent_url,
}
core.value('config', config);
core.config(function( $interpolateProvider ) {
$interpolateProvider.startSymbol( "[[" ).endSymbol( "]]" );
});
core.config(function( $httpProvider ) {
$httpProvider.interceptors.push('coreHttpInterceptor');
});
This is my ui.js code:
var ui = angular.module('ui',[ 'core' , 'ui.bootstrap' ]);
ui.directive( "shLoadify" , function( httpServiceInformationProvider ){
return {
restrict: "AE",
link: function(scope, element, attrs) {
element.bind( "click", function() {
element.text("Loading...");
element.prop( "disabled", true );
});
},
controller: function($scope) {
$scope.$watch('httpServiceInformationProvider', function(oldValue, newValue){
console.log(oldValue + ' ' + newValue);
}, true);
}
}
});
As you can see i am trying to access requestCount property of httpInfomationService from within my controller using $scope.watch.
The problem is newValue and oldValue is always null. Why is that so?
Approach 1
If you want to perform some action whenever your requestCount variable gets changed which is part of service, you need to broadcast/emit which then you can listen through on. But in this case you need to pass the scope in your service which is not recommended.
var app = angular.module('app',['app1']);
app.service('myService',function($rootScope){
this.requestCount=1
this.incrementRequestCount=function(){
this.requestCount++
$rootScope.$broadcast('requestCountChanged', { message: this.requestCount });
}.bind(this)
})
app.controller('myController',['$scope','myService',function($scope,myService){
$scope.$on('requestCountChanged', function(event, args) {
// You will find the updated requestCount in args
});
$scope.click= myService.incrementRequestCount;
}])
var app1 = angular.module('app1',[]);
app1.controller('mySecondController',['$scope','myService',function($scope,myService){
$scope.$on('requestCountChanged', function(event, args) {
// You will find the updated requestCount in args
});
}])
Approach 2
Without passing scope in the service
var app = angular.module('app',['app1']);
app.service('myService',function(){
this.requestCount=1
this.incrementRequestCount=function(){
debugger;
this.requestCount++
}.bind(this)
})
app.controller('myController',['$scope','myService','$rootScope',function($scope,myService,$rootScope){
$scope.click=function(){
myService.incrementRequestCount();
$rootScope.$broadcast('requestCountChanged', { message: myService.requestCount });
}
}])
var app1 = angular.module('app1',[]);
app1.controller('mySecondController',['$scope','myService',function($scope,myService){
$scope.$on('requestCountChanged', function(event, args) {
// You will find the updated requestCount in args
});
}])
Approach 3
You can only attach watch to those properties which are actually in the scope otherwise you cannot have watch for those properties. So just add requestCount on you scope than you can easily detect its changes using watch and then use broadcast/emit approach.
var app = angular.module('app',['app1']);
app.service('myService',function(){
this.requestCount=1
this.incrementRequestCount=function(){
debugger;
this.requestCount++
}.bind(this)
})
app.controller('myController',['$scope','myService','$rootScope',function($scope,myService,$rootScope){
$scope.requestCount=myService.requestCount
$scope.$watch('requestCount',function(n,o){
debugger;
if(n!=o)
{
$rootScope.$broadcast('requestCountChanged', { message: n });
}
})
$scope.click=function(){
myService.incrementRequestCount();
$scope.requestCount=myService.requestCount
}
}])
var app1 = angular.module('app1',[]);
app1.controller('mySecondController',['$scope','myService',function($scope,myService){
$scope.$on('requestCountChanged', function(event, args) {
// You will find the updated requestCount in args
});
}])
I have a kendo grid, which is controlled by an angular controller:
<div>
<kendo-grid options="mainGridOptions" k-data-source="gridData">
</kendo-grid>
</div>
UPDATE
The data is loading, but the grid isn't rendered. (I also had a term-mismatch and treated sectors as status.
"use strict";
angular.module("tenderApp")
.controller("tenderCtrl", ["$scope", "adalAuthenticationService", "tenderSvc", "$q", function ($scope, adalService, tenderSvc, $q) {
$scope.mainGridOptions = null;
$scope.gridSource = null;
$scope.statusData = null;
function loadStatusData() {
return tenderSvc.getSector()
.then(function(sector) {
$scope.sectorData = sector.data.map(function (obj) {
return {
text: obj.bezeichnung,
value: obj.id
};
});
return $scope.sectorData;
});
}
function loadGridSource(result) {
return tenderSvc.getItems()
.then(function (res) {
$scope.gridSource = res.data;
return res.data;
});
}
loadStatusData()
.then(loadGridSource)
.then(function (res) {
//both properties are available at this point
console.log($scope.gridSource);
console.log($scope.sectorData);
$scope.gridData = new kendo.data.DataSource({
transport: {
read: function (e) {
e.success($scope.gridSource);
},
//...
},
//...
});
$scope.mainGridOptions = {
toolbar: ["excel"],
dataSource: $scope.gridData,
columns: [
{ field: "sektor", title: "Sektor", values: $scope.sectorData },
{ command: ["edit"], title: "Aktionen", width: "120px" }
]
};
});
}]);
The problem is, the last call, which should populate the grid, does not work properly. The console.log calls show that the data is loaded, but the grid does not show up.
Nice one, now I learn how to do chaining from you. As for your problem, we don't need to use transport/read. Instead, we can load the data separately and set it to the grid dataSource like this. Note that, please don't put k-data-source="gridData" in your grid html attribute since you already have grid options.
HTML:
<div><kendo-grid options="mainGridOptions" k-data-source="gridData">
</kendo-grid></div>
JS:
"use strict";
angular.module("tenderApp")
.controller("tenderCtrl", ["$scope", "adalAuthenticationService", "tenderSvc", "$q", function ($scope, adalService, tenderSvc, $q) {
$scope.mainGridOptions = null;
$scope.gridSource = null;
$scope.statusData = null;
$scope.mainGridOptions = {
dataSource: new kendo.data.DataSource(),
toolbar: ["excel"],
columns: [
{ field: "sektor", title: "Sektor", values: $scope.sectorData },
{ command: ["edit"], title: "Aktionen", width: "120px" }
]
};
function loadStatusData() {
return tenderSvc.getSector()
.then(function(sector) {
$scope.sectorData = sector.data.map(function (obj) {
return {
text: obj.bezeichnung,
value: obj.id
};
});
return $scope.sectorData;
});
}
function loadGridSource(result) {
return tenderSvc.getItems()
.then(function (res) {
$scope.gridSource = res.data;
return res.data;
});
}
loadStatusData()
.then(loadGridSource)
.then(function (res) {
$scope.mainGridOptions.dataSource.data($scope.gridSource);
});
}]);
I need to remake this functoin 'i18n' to a factory but so i return a value instead of just setting it with this.
Thanks in advance!
services.service('i18n', function() {
var self = this;
this.setLanguage = function(language) {
$.i18n.properties({
name: 'messages',
path: 'i18n/',
mode: 'map',
language: language,
callback: function() {
self.language = language;
}
});
};
this.setLanguage('nl');
});
Try to set up your service like this:
myApp.service('LangService', function() {
var setLang = function(lang) {
// return whatever you want
}
return {
setLang: setLang
};
});
Then you can call your method setLang from anywhere:
LangService.setLang('nl');
I am building a notecard application and for some reason my ng-change is not firing at all. I cannot figure out what the issue is. I tried breakpoints in the JS to verify that it is not actually firing. I'm positive it's got to be a something small I missed. I just need a second pair of eyes on it.
Here is the JS
var app = angular.module('catalyst', ['faye']);
app.factory('Faye', [
'$faye', function($faye) {
return $faye("http://localhost:9292/faye");
}
]);
app.directive('stickyNote', function(Faye) {
var linker = function(scope, element, attrs) {
element.draggable({
stop: function(event, ui) {
Faye.publish('/ui/board', {
id: scope.note.id,
x: ui.position.left,
y: ui.position.top
});
}
});
Faye.subscribe('/ui/board', function(data) {
// Update if the same note
if(data.id == scope.note.id) {
element.animate({
left: data.x,
top: data.y
});
}
});
// Some DOM initiation to make it nice
element.css('left', '10px');
element.css('top', '50px');
element.hide().fadeIn();
};
var controller = function($scope) {
// Incoming
Faye.subscribe('/ui/board', function(data) {
// Update if the same note
if(data.id == $scope.note.id) {
$scope.note.title = data.title;
$scope.note.body = data.body;
}
});
// Outgoing
$scope.updateNote = function(note) {
Faye.publish('/ui/board', note);
};
$scope.deleteNote = function(id) {
$scope.ondelete({
id: id
});
};
};
return {
restrict: 'A',
link: linker,
controller: controller,
scope: {
note: '=',
ondelete: '&'
}
};
});
app.controller('MainCtrl', function($scope, Faye) {
$scope.notes = [];
// Incoming
Faye.subscribe('/ui/board', function(data) {
$scope.notes.push(data);
});
Faye.subscribe('/ui/board', function(data) {
$scope.handleDeletedNoted(data.id);
});
// Outgoing
$scope.createNote = function() {
var note = {
id: new Date().getTime(),
title: 'New Note',
body: 'Pending'
};
$scope.notes.push(note);
Faye.publish('/ui/board', note);
};
$scope.deleteNote = function(id) {
$scope.handleDeletedNoted(id);
Faye.publish('/ui/board', {id: id});
};
$scope.handleDeletedNoted = function(id) {
var oldNotes = $scope.notes,
newNotes = [];
angular.forEach(oldNotes, function(note) {
if(note.id != id) newNotes.push(note);
});
$scope.notes = newNotes;
}
});
Here is the ui/board.html.haml
%body{"ng-controller" => "MainCtrl"}
%nav.top-bar{"data-topbar" => ""}
%ul.title-area
%li.name
%h1
%a{:href => "#"} AngularJS CollabBoard
%li.toggle-topbar.menu-icon
%a{:href => "#"}
%span Menu
%section.top-bar-section
%ul.right
%li
%a#createButton{"ng-click" => "createNote()"} Create Note
.alert-box.success.radius.sticky-note{"ng-repeat" => "note in notes track by $index", :note => "note", :ondelete => "deleteNote(id)", "sticky-note" => ""}
%button.close{"ng-click" => "deleteNote(note.id)", :type => "button"} ×
%input.title{"ng-change" => "updateNote(note)", "ng-model" => "note.title", :type => "text"}
%textarea.body{"ng-change" => "updateNote(note)", "ng-model" => "note.body"} {{note.body}}
There is a lot to look at here, I believe you have scoping issue. For one, you are not using transclude on your directive and therefore your child elements would not be included in your compiled directive. I noticed also that you have deleteNote on your main controller and are delegating upwords to the maincontroller but then put updateNote on just the directive. I imagine your delete is working. You are using ng-repeat which does create a child scope for each "note".