AngularJS - Non-http Service Not Updating Scope Variables - angularjs

I've just been starting on AngularJS and I'm still trying to understand creating services. From this and this, my understanding is as long as changes to variables are within Angular, there is no need to $watch them. I copied code from here, and modified it to see if I can get my first service to work:
myApp.factory('ListService', function() {
var ListService = {};
var list = ['a', 'b', 'c'];
ListService.addItem = function(item) { list.push(item); }
ListService.size = function() { return list.length; }
ListService.size1 = list.length;
return ListService;
});
function Ctrl1($scope, ListService) {
$scope.message = ListService.size();
$scope.addItem = function(){
ListService.addItem('d');
console.log("size() is " + ListService.size());
console.log("size1 is " + ListService.size1);
}
}
function Ctrl2($scope, ListService) {
$scope.message = ListService.size1;
}
The html is simply:
<div ng-controller="Ctrl1"> Count is: {{ message }}
<input type="button" ng-click="addItem">
</div>
<div ng-controller="Ctrl2"> Count is: {{ message }}
</div>
When clicking the button, the console log shows the correct counts, but "messages" remain the same. The original code is supposed to be contrived and was meant to show that services could be used to share code across controllers.
So my questions is, why isn't this working? I apologize if I missed something very simple. I'm a beginner and I'm still trying to get a hang of things.

Instead
$scope.message = ListService.size();
try
$scope.getCount = function () {
return ListService.size();
};
and then in view:
Count is: {{getCount()}}
It is because your $scope.message is primitive value that contains ListService's size at the moment of controller initialization.
(I'm realy bad in English speaking, so sorry for short answer).

Related

AngularJs Component and angularjs-dropdown-multiselect

I am new to AngularJs world and was trying to use angularjs-dropdown-multiselect inside component.
Component's HTML looks like:
<div>
<select id="statusSelection" class="form-control"
ng-options="status.name for status in $ctrl.statuses track by status.id"
ng-model="$ctrl.status" ng-change="$ctrl.filterChanged()"></select>
</div>
<div ng-dropdown-multiselect="" options="$ctrl.categories" selected-model="$ctrl.category"
events="$ctrl.events">
</div>
Event on status changed and category will call the same action.
MultiselectController.prototype.filterChanged = function() {
this.onFilterChange({
status: this.status,
category: this.category});
};
MultiselectController.prototype.events = {
onItemSelect: function(item) {
filterChanged();
},
onItemDeselect: function(item) {
filterChanged();
}
};
When I try to run the above code and change the status, the code works as expected but fails during Category change(error in console).
Error message: ReferenceError: filterChanged is not defined
Angular version: 1.5.8
angularjs-dropdown-multiselect: 1.11.8
Plunker: http://plnkr.co/edit/JL7N6M?p=preview
Thanks for helping me out here.
I have created an instance variable and initialize it to instance of Controller.
var _instance;
function MultiselectController($scope) {
this.statuses = testMultiselect.statuses;
this.categories = testMultiselect.categories;
this.$scope = $scope;
this.setDefault();
_instance = this;
}
Now, I am using this instance variable to access the functions on Controller.
MultiselectController.prototype.events = {
onItemSelect: function(item) {
_instance.filterChanged();
},
onItemDeselect: function(item) {
_instance.filterChanged();
}
};
I am not completely happy with this as there should be better way to do the same but until I find, I will keep this.
Updated Plunker: http://plnkr.co/edit/D7BKI9?p=preview

Using ngReact with ASP .NET MVC

I have an MVC test project that I am trying to use React components inside Angular directives. It will render the directive, but any props I pass in are undefined. Here are my files:
~/Scripts/Directives/HelloDirective.js:
var Hello = React.createClass({
render: function () {
return React.DOM.span(null,
'Hello ' + this.props.email
);
}
});
angular.module('App').value('Hello', Hello);
angular.module('App')
.directive( 'hello', function( reactDirective ) {
return reactDirective( Hello, ['email'] );
});
My folder structure for my views goes like this:
~/Views/Dashboard/Index.cshtml - this is my main view that has ng-view
~/Views/Dashboard/Dash.cshtml - this gets put inside the main view
Inside Dash.cshtml I have
<div ng-controller="DashboardController" class="btn-group">
<hello email="{{name}}"></hello>
</div>
Here is my DashboardController.js file:
angular.module("App")
.controller("DashboardController", ['$scope', 'Welcome', '$cookies', function ($scope, Welcome, $cookies) {
Welcome.name().success(function (data) {
$scope.name = data.name;
});
$scope.ChangeName = function (val) {
Welcome.EditName(val).success(function (data) {
});
};
/*
$scope.isOff() = function () {
var value = $cookies.get('Off');
return value === null;
}
$scope.Off = function () {
$cookies.put('Off', 'This turns the green button off');
}
$scope.On = function () {
$cookies.remove('Off');
}
*/
}]);
Once the page has finished loading up all that is rendered is Hello undefined.
For some reason the email prop inside the hello tag is not being read or recognized or something.
I have already tested to make sure that my WelcomeFactory returns data by just displaying {{name}} on the screen and it works just fine.
Can someone tell my where I went wrong?
Thanks!
So the answer to this question was annoyingly simply. It really came down to syntax. What I mean by that was the React Component I had looked like this:
<hello email="{{name}}"></hello>
I kept getting undefined for the email, as it turns out the issue was the curly braces. Once I took those out the React Component looked like this:
<hello email="name"></hello>
Then I started to get a value output on the screen.
Hope this helps someone else looking into this issue!

angular-meteor 1.3 $meteor.object the new way

There is something I'm probably missing but I try to access a single document from my mongo collection Tribunaux reactively without $stateParams in my variable modifTrib. I got the tribunalId field when I clicked on a button. So before I click my variable is null in my controller.
Here is what I did :
angular
.module('app')
.controller('tribunauxController', tribunauxController);
tribunauxController.$inject = ['$scope', '$reactive', '$mdDialog'];
function tribunauxController($scope, $reactive, $mdDialog)
{
$reactive(this).attach($scope);
var vm = this;
vm.TribunalModify = TribunalModify;
vm.tribunalId = null;
vm.helpers({
tribunaux: () => {
return Tribunaux.find({});
}
});
vm.helpers({
modifTrib () {
return Tribunaux.findOne(tribunalId);
}
});
function TribunalModify(tribId){
vm.tribunalId = tribId;
} }
I can't get this to work.
Need a little help thanks!
UPDATE : Here is the interesting part of my HTML
<md-list-item class="md-2-line" ng-click="vm.TribunalModify(tribunal._id)"
ng-repeat="tribunal in vm.tribunaux">
<div class="md-list-item-text">
<h3>Tribunal d'instance de {{tribunal.label}}</h3>
<p>{{tribunal.address}}</p>
</div>
</md-list-item>
You can change 2 things:
Merge the helpers into one helpers definition (I think it's just looks nicer)
tribunalId has to be reactively in order to make the helper re-run. there are few ways of doing that (we are just discussing it here: https://github.com/Urigo/angular-meteor/issues/955) but for now, the easiest way is to use getReactively like that:
return Tribunaux.findOne(getReactively("tribunalId"));

Refresh list after server callback in AngularJS

I fetch a collection from the server and I would like to get detail for each item. All requests are received correctly, but the paragraph Loading... doesn't hide.
<h2 ng-repeat-start="server in hypervisors track by server.ip | orderBy:server.ip">
{{server.ip}}
</h2>
<div ng-repeat-end>
<p ng-hide="{{server.loaded}}" class="ng-hide">Loading...</p>
When I uncomment the line in controller before post everything works fine.
vmwareStatusApp.controller('Home', function ($scope, $http) {
$http.post('Home/ListHypervisors').success(function (data) {
$scope.hypervisors = data;
$scope.listLoaded = true;
$scope.hypervisors.forEach(function (item) {
//item.loaded = true; // this line works
$http.post('Home/HostInfo', { 'ip': item.ip }).success(function (data) {
$scope.hypervisors[0].loaded = true;
item.loaded = true;
item.detail = data;
})
.error(function(data) {
item.loaded = true;
item.error = data;
item.displayError = true;
});
});
});
});
There are many posts about refreshing view, but I haven't found any working for me. Neither anti-patter with calling $digest() didn't work, because of multiple callback. Which part of AngularJS tutorial have I skipped?
Just remove the braces from your ng-hide like this
ng-hide="server.loaded"
ng-hide and angular directives should be read like this :
ng-directive = "somethingAngularWillInterpret"
The opposite exemple is in your HTML angular will not know what he should interpret instead of just showing some text
<b>server.loaded</b> will show a bold "server.loaded"
To notice angular that he need to interpret we will use the braces
<b>{{somethingAngularWillInterpret}}</b> will show a bold result of the interpretation
EDIT :
So doing this ng-hide="{{server.loaded}}" is probably saying to angular to interpret the result of the server.loaded interpretation like a var named true or a var named false (just speculation, i need to try it).
Just tested it, this just lead to a syntax error.

AngularJS Service to Service with a delay

I am currently facing a problem with my project's design.
I am using angularjs framework and my task is to provide a translations for a webpage, but the translations need to be provided form the xml file o the BE side.
So since I#ve found out that angulars i18n is configurable on the FE side i had to use another strategy.
I've decided to make a service which fetches the data during a resolve period before everything else is loaded:
app.factory('dictionaryService', ['$http', '$rootScope', function ($http, $rootScope) {
return {
getDictionary: function (defaultLanguage) {
var chosenLanguage = null;
if (angular.isUndefined($rootScope.defaultLanguage) || $rootScope.defaultLanguage == null) {
chosenLanguage = defaultLanguage;
$rootScope.defaultLanguage = chosenLanguage;
} else {
chosenLanguage = $rootScope.defaultLanguage;
}
var translation = new Array();
translation[chosenLanguage] = new Array();
return $http.get('Translation/GetCurrentDictionary/', {
params: {
language: chosenLanguage
}
});
},
GetLanguagesSetup: function () {
return $http.get('Translation/GetLanguagesSetup/');
}
}
}]);
and then resolve it as follows:
$routeProvider.when("/diagnose", {
controller: "diagnoseCtrl",
templateUrl: "/app/views/diagnose.html",
resolve: {
startupData: function (dictionaryService, $q) {
var def = $q.defer();
var translation = new Array();
var startupData = new Array();
var defaultLanguage = "EN";
var dict = dictionaryService.getDictionary(defaultLanguage).then(function (JSONData) {
var keys = Object.keys(JSONData.data.data);
var chosenLanguage = JSONData.data.lang;
translation[chosenLanguage] = {};
for (i = 0; i < keys.length; i++) {
translation[keys[i]] = JSONData.data.data[keys[i]];
}
startupData['translations'] = translation;
def.resolve(startupData);
}).catch(function (e) {
console.log("Translation fetching exception, " + e);
return $q.reject(e);
});
return def.promise;
}
}
});
So as you can see I am storing my fetched translations in a startupData. Then in a controller which is using it I am assigning this data to the $rootScope. It seems already here as a not the best solution, but I could not come up with a different one
Then I have created a translation service which gets the direct translation text:
app.factory('translationService', ['$rootScope', '$http', function ($rootScope, $http) {
var translations = null;
return {
getText: function (key) {
if ($rootScope.cachedTranslations == undefined) {
return key;
}
var result = $rootScope.cachedTranslations[key];
if (result == null) {
return key;
} else {
return result;
}
}
}
}]);
The biggest problem with this solution is, that I am not using promises, but I do not want to make an http query to BE for each translation.
The other problem is with the html template provided by the designers:
<body ng-controller="mainController">
<loading-screen ng-show="!isDataLoaded"></loading-screen>
<div id="header" class="headerView" ng-controller="headerController" ng-show="isDataLoaded">
some header stuff
...
<button ng-bind="option1" ng-click="redirectTo('#subpage1')"></button>
<button ng-bind="option2" ng-click="redirectTo('#subpage2')"></button>
<button ng-bind="option3" ng-click="redirectTo('#subpage3')"></button>
<button ng-bind="language" ng-if="availableLanguages.length > 1" ng-repeat="language in availableLanguages" ng-click="setLanguage(language)"></button>
</div>
</div>
<
<div id="content" ng-view ng-show="isDataLoaded">
</div>
<footer id="footer" class="footer" ng-show="isDataLoaded">
<status-bar></status-bar>
</footer>
Resolve applies only for ng-views's controller, but header stuff needs to be translated as well, so I need to make a headerCtrl somehow wait before it tries to apply translations.
So I have made another unpopular decision to inform all controllers about the finished startup via a broadcast message and to wait until it is all done while showing the loading screen.
It looks fine and is pretty responsive (1sec per startup is acceptable at this point).
The problem is, that I see many design mistakes with this attempt and I just can not come up with the better design.
So my main question is:
How can I make it better? 1st service returns a whole array which is used by the 2nd service so I do not know how to combine it with promises?
I am afraid that with the development of the application I will find myself in a global variables and global events hell
Thanks in advance for your help!
It seems like you are looking for the angular-translate-loader-static-files extension for angular-translate. See the documentation here.
This together with proper configuration of $translateProvider will allow you to fetch json files with translations from the backend or even swap translations on demand - for example user changes language setting, controller reconfigures $translateProvider. Your job is done - everything will be fetched and updated automatically without a page reload.

Resources