Factory Array can be pushed but not replaced - javascript

I have this factory
DatosFactory.js
(function() {
'use strict';
angular.module('InmoManager')
.factory('DatosFactory', function($http, $location) {
var datos = {
propiedadesFiltradas: []
}
...
datos.getPropiedadesFiltradas = function(){
return datos.propiedadesFiltradas;
}
datos.setPropiedadesFiltradas = function(data){
datos.propiedadesFiltradas.length = 0;
datos.propiedadesFiltradas.push(data);
}
return datos;
})
})();
This controller
SidebarController.js
(function() {
'use strict';
angular.module('InmoManager')
.controller('SidebarController', function($http, $scope, DatosFactory) {
var sidebarCtrl = this;
sidebarCtrl.toggleSidebar = function(){
$('#wrapper').toggleClass('toggled');
}
sidebarCtrl.propiedades = DatosFactory.getPropiedadesFiltradas();
});
})();
Making this work
pageSidebar.html
<li class="item" ng-repeat="propiedad in sidebarCtrl.propiedades[0] | orderBy:'titulo'">
This works great!, but, i want to change this:
ng-repeat="propiedad in sidebarCtrl.propiedades[0]"
to
ng-repeat="propiedad in sidebarCtrl.propiedades"
and this
datos.setPropiedadesFiltradas = function(data){
datos.propiedadesFiltradas.length = 0;
datos.propiedadesFiltradas.push(data);
}
to
datos.setPropiedadesFiltradas = function(data){
datos.propiedadesFiltradas = data;
}
But when i make this, the variable sidebarCtrl.propiedades get's undefined (doesn't update when i call datos.setPropiedadesFiltradas()

When you reassign datos.propiedadesFiltradas = data; you break the object reference, and as the result datos.propiedadesFiltradas is no longer points to the object Angular set up bindings to.
On the other hand, when you push object reference stays untouched, and Angular's changes tracking engine can detect changes and rerender view.
One more thing. I would recommend you to use ngClass directive instead of $('#wrapper').toggleClass('toggled');:
sidebarCtrl.toggleSidebar = function() {
sidebarCtrl.toggle = !sidebarCtrl.toggle;
}
and in HTML
<div id="wrapper" ng-class={toggled: toggle}>...</div>

Because of dfsq answer i assume that all i wanted it's not possible, but i found this "partial" solution
With this in the factory:
datos.setPropiedadesFiltradas = function(data){
datos.propiedadesFiltradas.length = 0;
datos.propiedadesFiltradas.push.apply(datos.propiedadesFiltradas,data);
}
i could change this:
ng-repeat="propiedad in sidebarCtrl.propiedades[0]"
to
ng-repeat="propiedad in sidebarCtrl.propiedades"

Related

angularjs 1.6 two way binding of model doesn't update when changed inside a non angular event

angularjs code
var app = angular.module("testApp", []);
app.controller('captureCtrl', function () {
var vm = this;
vm.obj = {
show: false
};
addressControls.control.listen('populate', function (address, variations) {
vm.line1 = address.Line1;
vm.line2 = address.Line2;
vm.city = address.City;
vm.postcode = address.PostalCode;
vm.obj.show = true;
});
vm.test = function () {
vm.obj.show = true;
}
});
vm.obj.show value in the view doesn't get updated when changed inside the 'populate' event, but it does get updated inside vm.test function. How can I get this to work and why won't binding get updated in the view? I'm using angularjs 1.6.
Try $scope.apply().
$scope.$apply(function () {
//Your Code here
});
EDIT 1: I'm sorry--I completely overlooked something. You're using "this" instead of "$scope".
EDIT 2: Since it's a non-angular function, you definitely need a $scope.$apply() in there.
Try doing this instead:
var app = angular.module("testApp", []);
app.controller('captureCtrl', function ($scope) {
$scope.obj = {
show: false
};
addressControls.control.listen('populate', function (address, variations) {
$scope.line1 = address.Line1;
$scope.line2 = address.Line2;
$scope.city = address.City;
$scope.postcode = address.PostalCode;
$scope.obj.show = true;
$scope.$apply();
});
$scope.test = function () {
$scope.obj.show = true;
};
});
In general, use "$scope" if you want to expose properties for your DOM to work with.

Pass $scope value from controller to a service function

I need to pass a scope value to a service, what I'm doing now is declearing the service's function in the controller and passing the scope value as a parameter to this function. Here is the code
HTML code
<md-datepicker ng-model="dateDebut" md-placeholder="Enter date"> </md-datepicker>
<md-datepicker ng-model="dateFin" md-placeholder="Enter date" ></md-datepicker>
Controller code
app.controller('graphCtrl', function($scope, $stateParams, graphDetails, $filter,$http) {
var self = this;
self.dateDebut = $scope.dateDebut;
self.dateFin = $scope.dateFin;
var mettreAJour = graphDetails.mettreAJour(self.dateDebut, self.dateFin);
$scope.labels = mettreAJour.labels;
$scope.data = mettreAJour.data;
});
Service code
app.factory('graphDetails', function($filter, $http) {
var labels = [];
var data = [
[]
];
return {
mettreAJour: function(dateDebut, dateFin) {
if (dateDebut && dateFin) {
var dd = $filter('date')(dateDebut, 'yyyy-MM-dd;HH:mm:ss');
var df = $filter('date')(dateFin, 'yyyy-MM-dd;HH:mm:ss');
var dif = dateFin.getDate() - dateDebut.getDate();
//do somthing with labels and data
return {
labels : labels,
data : data
};
}
}
};
});
So I get as an error labels is not defined, and if I comment it I get this error:
Cannot read property 'getDate' of undefined
which means the code does not recognize dateFin nor dateDebut.
Is there another way to pass the scope to the service, or am I missing something in my current code?
If I understand the question correctly you need to somehow reevalute values when either dateDebut or dateFin properties of scope change.
To achive this you can use $watch or $watchGroup methods of the scope. Simplified Demo.
For example
app.controller('graphCtrl', function($scope, graphDetails) {
// start watcher
$scope.$watchGroup(['dateDebut', 'dateFin'], function(args) {
var debut = args[0], fin = args[1];
angular.extend($scope, graphDetails.mettreAJour(debut, fin))
})
})
Most probably this is because you are trying to return labels from mettreAJour but it is not aware of labels & data .
Hope this below snippet will be useful.
app.factory('graphDetails', function($filter, $http) {
var _graphDeatilsObject = {};
_graphDeatilsObject.labels = [];
_graphDeatilsObject.data = [
[]
];
_graphDeatilsObject.mettreAJour = function(dateDebut, dateFin) {
// Rest of the code
}
return _graphDeatilsObject;
});
Also take a look at inline array annotation which is required if you are minifying the code

How do I add result to my scope ng-click?

This is a relatively simple piece of code that calls a service and returns some data. I need to set the $scope with the result of the data. Is there an easy way to set this data to the scope without resorting to to binding the scope to the function in the then clause?
Angular Code
(function () {
var app = angular.module('reports', []);
var reportService = function($http, $q) {
var service = {};
service.getMenuData = function() {
var deffered = $q.defer();
$http.get('/Report/MenuData').success(function(data) {
deffered.resolve(data);
}).error(function(data) {
deferred.reject("Error getting data");
});
return deffered.promise;
}
return service;
};
reportService.$inject = ['$http', '$q'];
app.factory('reportService', reportService);
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = function(e) {
reportService.getMenuData().then(function(data) {
// Need to set the $scope in here
// However, the '$scope' is out of scope
});
}
};
reportMenuController.$inject = ['$scope', '$http', 'reportService'];
app.controller('ReportMenuController', reportMenuController);
})();
Markup
<div>
<div ng-controller="ReportMenuController">
<button ng-click="getMenuData()">Load Data</button>
</div>
</div>
There is absolutely no problem to set the $scope from within the function passed to then(). The variable is available from the enclosing scope and you can set your menu data to one of its fields.
By the way: You should consider to use then() instead of success() for your http request. The code looks much nicer because then() returns a promise:
service.getMenuData = function() {
return $http.get('/Report/MenuData').then(function(response) {
return response.data;
}, function(response) {
deferred.reject("Error getting data");
});
}
success() is deprecated by now.
I didn't notice the small detail missing in the plunker where my code was different.
(function () {
...
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = getMenuData;
function getMenuData(e) {
reportService.getMenuData().then(function(data) {
// Now I have access to $scope
});
}
};
...
})();
Notice the changes to the two lines as below:
$scope.getMenuData = getMenuData;
function getMenuData(e) {
This also begs a small question which is, "Why is it okay to set getMenuData to the $scope before it is declared?

Data Binding not happening between service and controller in angularjs

I am trying to use a service instead of a factory to perform two way data binding, I have seen may tutorials online on using a factory but I prefer using a service instead of a factory, so far I have come up with the following pattern to perform the binding but, on doing console.log() i found that the data from the service doesn't bind to the data on the controller.
controller: ['$scope','LeadsService','ServiceVehicleModels', function($scope, LeadsService, ServiceVehicleModels) {
$scope.colorList = ServiceVehicleModels.colors;
$scope.yearsList = ServiceVehicleModels.years;
$scope.$watch(function() { return ServiceVehicleModels.colors }, function(data) {
return $scope.colorList = data.colors;
},true);
};
Here is my service code
exports.service = function() {
this.colors = [];
this.years = [];
this.trims = [];
var scope = this;
this.setColors = function(colorsArr) {
scope.colors = colorsArr;
};
this.setYears = function(yearsArr) {
scope.years = yearsArr;
};
};
What changes do i need to make to make the data binding work?
You have issue in watcher. This should solve bindings:
$scope.$watch(function() { return ServiceVehicleModels.colors }, function(colors) {
return $scope.colorList = colors;
},true);

how to update $scope object in a view after a promise is resolved in angular?

i have a simple situation where in the controller I have:
$scope.loadEvents = function () {
var items = listEvents(id);
items.then(function (data) {
$scope.test= data;
});
};
In the view I do:
<h1>{{test}}</h1>
but $scope.test is not available yet. If I do $scope.apply() I get this error
the actual error is that {{test}} doesn't show, i guess because is undefined
any ideas?
You can do
$scope.test = [];
$scope.loadEvents = function () {
var items = listEvents(id);
items.then(function (data) {
$scope.test= data;
});
};
and in view
<h1 ng-if="test">{{test}}</h1>
to make it visible only when test is loaded

Categories

Resources