I am working on a note-taking app.
I want my app to delete all checked radios on clicking the 'Remove' link. An insight into the code:
HTML:
<p>[ <a href='#/home'>Cancel</a> | <a href='#/home/edit' ng-click='remove()'>Remove</a> ]</p>
<table border='0'>
<tbody>
<tr ng-repeat='note in notes'>
<td>
<input type='radio' ng-model='note.rmv'></input>
</td>
<td>{{note.text}}</td>
</tr>
</tbody>
</table>
Controller:
app.controller('editCtrl', ['$scope', 'notes', function($scope, notes) {
$scope.notes = notes.notes;
$scope.remove = function() {
for (var i = 0; i < $scope.notes.length; ++i) {
if ($scope.notes[i].rmv) {
delete $scope.notes[i];
notes.getLost($scope.notes[i]._id);
}
}
};
}]);
Factory:
app.factory('notes', ['$http', function($http) {
var t = {
notes: []
};
t.getLost = function(id) {
return $http.delete('/home/edit').success(function(data) {
return t.getAll();
});
};
return t;
};
What might be doing wrong here?
Well, there are a lot of mistakes in your code, I think you should refactor your code. Also there's no necessity of delete the item in Javascript, you can delegate it all to your back-end since you already have the function to getAll objects.
See the code below to take it as example:
(function() {
angular
.module('app', [])
.controller('editCtrl', editCtrl)
.factory('notes', notes);
editCtrl.$inject = ['$scope', 'notes'];
function editCtrl($scope, notes) {
getAll(); // <- initialization of notes
$scope.remove = remove;
function getSuccess(response) {
console.log('success');
}
function getError(response) {
console.log('error');
}
function remove() {
for (var i = 0; i < $scope.notes.length; ++i) {
if ($scope.notes[i].rmv) {
notes.getLost($scope.notes[i]._id)
.then(getSuccess)
.catch(getError);
}
}
fetchData();
}
function fetchData() {
notes.getAll()
.then(function(response) {
$scope.notes = response.data;
})
.catch(function(response) {
console.log('error');
});
}
}
notes.$inject = ['$http'];
function notes($http) {
var factory = {
getAll: getAll,
getLost: getLost
};
return factory;
function getAll() {
return $http.get('url_to_fetch');
}
function getLost(id) {
// It should only return the promise, not more than that
return $http.delete('/home/edit/' + id); // <- is this URL correct?
}
}
})();
You have a typo:
if($notes.notes[i].rmv) {
Should be:
if($scope.notes[i].rmv) {
Related
I am trying to activate a checkbox from a controller that lives in another controller. For example, I have a card named information technology under a separate controller and when I click this I want it to route to another page that has a checkbox for information technology from another controller and I want it checked as it renders the page.
The application architecture is very lengthy so I wont include any code base here. But I would like to know an approach I can take.
This is the controller where I want the logic to live and to mark a text box as checked (which lives on another controller).
angular
.controller("mycontroller", mycontroller);
mycontroller.$inject = [
"$scope"
];
// getting the getData() data
$scope.getData = function (data, type) {
console.log("whats this data about in getData(data) ", data)
$scope.query = data.name;
if (data.checked == undefined) {
data.checked = true;
}
}
Below: Is the controller where the checkbox controller lives
angular
.controller('supplierIntelligenceCtrl', function ($scope, $q, FetchData, dataStore, SharedService,
$document, $window, $state, $rootScope, $timeout, DataCache,
$filter, $interval, $localStorage, $http) {
$scope.getData = function (data, type) {
console.log("whats this data about in getData(data) ", data)
$scope.query = data.name;
if (data.checked == undefined) {
data.checked = true;
}
}
$scope.apply = function (type) {
$scope.select = false;
$scope.bigres = 0;
$scope.mobFil = 3;
$scope.applyFilter(type);
}
$scope.disableApply = false;
$scope.disableApply2 = false;
$scope.applyFilter = function (type) {
console.log("this is type ", type)
if (type == 'industries') {
$scope.filters.industries = $scope.industries.filter(function (e) {
console.log("this is e ", e.checked)
return e.checked;
}).map(function (f) {
console.log(" this is f >>>> ",
f)
return f.id
})
$scope.filters.countries = [];
if ($scope.countries != undefined) {
$scope.countries = $scope.countries.map(function (e) {
e.checked = false;
return e;
})
}
$scope.filters.cities = [];
if ($scope.cities != undefined) {
$scope.cities = $scope.cities.map(function (e) {
e.checked = false;
return e;
})
}
$scope.start = 0;
if ($scope.filters.industries.length > 0) {
$scope.callBackend();
$scope.disableApply2 = true;
FetchData.fetchDNBCountriesByIndustries('industries=' + $scope.filters.industries + '&size=').then(function (res) {
$scope.disableApply2 = false;
$scope.countries = res.data;
$scope.countriesPage += 10
}, function () {
$scope.disableApply2 = false;
});
} else {
$scope.callBackend();
}
}
if (type == 'countries') {
$scope.filters.countries = $scope.countries.filter(function (e) {
return e.checked;
}).map(function (f) {
return f.id;
})
$scope.filters.cities = [];
if ($scope.cities != undefined) {
$scope.cities = $scope.cities.map(function (e) {
e.checked = false;
return e;
})
}
$scope.start = 0;
if ($scope.filters.countries.length > 0) {
$scope.callBackend();
$scope.disableApply2 = true;
FetchData.fetchDNBCitiesByIndustriesAndCountries('industries=' + $scope.filters.industries + '&countries=' + $scope.filters.countries + '&size=').then(function (res) {
$scope.disableApply2 = false;
$scope.cities = res.data;
}, function () {
$scope.disableApply2 = false;
})
} else {
$scope.callBackend();
}
}
if (type == 'cities') {
$scope.filters.cities = $scope.cities.filter(function (e) {
return e.checked;
}).map(function (f) {
return f.id
})
$scope.start = 0;
$scope.callBackend();
}
if (type == 'classifications') {
$scope.filters.classifications = $scope.classifications.filter(function (e) {
return e.checked;
}).map(function (f) {
return f.statusCode;
})
$scope.start = 0;
$scope.callBackend();
}
}
}
Here is the HTML where the checkbox lives:
<div ng-repeat="data in industries ">
<input id="{{data.id}}in" type="checkbox" aria-invalid="false"
ng-model="data.checked"
ng-change="getData(data,'industry')">
<label for="{{data.id}}in">{{data.name}}</label>
</div>
Maybe Im missing the point here and perhaps am overlooking something. Im new to angularjs and need to implement this capability to route a button/card to another page that checks a checkbox filter.
Please - any advise would be great . :)
Here is an example of controllers sharing an array via a shared service injected by the dependency injector. Check the checkbox in one controller and it shows in the other.
angular.module('app', []);
angular.module('app')
.factory('dataService', [function () {
return {
data: [
{ prop: '1', checked: false },
{ prop: '2', checked: false },
{ prop: '3', checked: false },
{ prop: '4', checked: false }
]
};
}]);
angular.module('app')
.controller('controller1', ['dataService', function (dataService) {
this.data = dataService.data;
}]);
angular.module('app')
.controller('controller2', ['dataService', function (dataService) {
this.data = dataService.data;
}]);
angular.module('app')
.controller('controller3', ['dataService', function (dataService) {
this.toggleAll = () => {
dataService.data.forEach(item => item.checked = !item.checked)
};
}]);
[ng-controller] { display: inline-block; margin-right: 30px; vertical-align: top; }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="controller1 as ctrl">
<strong>Controller 1</strong>
<div ng-repeat="item in ctrl.data">
<label>Item {{item.prop}} <input type="checkbox" ng-model="item.checked"></label>
</div>
</div>
<div ng-controller="controller2 as ctrl">
<strong>Controller 2</strong>
<div ng-repeat="item in ctrl.data">
<label>Item {{item.prop}} <input type="checkbox" ng-model="item.checked"></label>
</div>
</div>
<div ng-controller="controller3 as ctrl">
<strong>Controller 3</strong>
<div>
<button ng-click="ctrl.toggleAll()">Toggle all</button>
</div>
</div>
</div>
Put industries as a property on a shared service that you inject into both of the controllers by the dependency injector. Then one controller can bind it to it's view and the other one can change the checked properties on them.
Since you are talking about redirection and then checking a check box, you can try either of below options
Send selection 'information technology' in query string to redirected page and check the check box
If you own a back end server then put the value in cookie and read it in your angular js app
Hope this helps.
I have a problem with my service in angular.
My service has the next code:
app.service("Utilidades", ['$http', '$window', function ($http, $window) {
return {
Get: function (urlAbsoluta, parametros, callback) {
var Utilidades = this;
$http
.get(app.UrlBase + urlAbsoluta, parametros)
.then(function (data) {
var Datos = angular.fromJson(data);
Utilidades.GuardarToken(Datos.Token);
callback(Datos);
});
},
ObtenerMenu: function () {
var Utilidades = this;
Utilidades.Get("Administracion/Api/Usuarios/Menu", {}, function (Datos) {
Datos = angular.fromJson(Datos.data);
if (Datos.Error == "") {
return Datos.Resultado;
} else {
return "";
}
});
}
}
}]);
Then, in my controller i have the next code:
app.controller('LoginCtrl', ['$scope', '$http', '$location', 'Utilidades',
function Iniciador($scope, $http, $location, Utilidades) {
var Li = this;
Li.Usuario = "";
Li.Contrasena = "";
Li.Error = "";
Li.MenuItems = [];
Li.Menu = function () {
Li. MenuItems = Utilidades.ObtenerMenu();
}
}]
);
When i run this, Li.MenuItems have undefined value and i don't know why.
Your return statements are in a function inside your ObtenerMenu method so the ObtenerMenu method is not actually returning anything. You need to provide a way to access the resulting value:
Service
app.service("Utilidades", ['$http', '$window', function ($http, $window) {
return {
Get: function (urlAbsoluta, parametros) {
var Utilidades = this;
// v------------ return statement here
return $http
.get(app.UrlBase + urlAbsoluta, parametros)
.then(function (data) {
var Datos = angular.fromJson(data);
Utilidades.GuardarToken(Datos.Token);
// v------------ return statement here
return Datos;
});
},
ObtenerMenu: function () {
var Utilidades = this;
// v------------ return statement here
return Utilidades.Get("Administracion/Api/Usuarios/Menu", {})
.then(function (Datos) {
if (Datos.Error == "") {
return Datos.Resultado;
} else {
return "";
}
});
}
};
}]);
In Controller
Li.Menu = function () {
Utilidades.ObtenerMenu()
.then(function (resultado) {
Li. MenuItems = resultado;
});
}
It's because ObtenerMenu function is asynchronous function. This function doesn't return anything initially (so undefined) and later, after some time when ajax request finishes, this function is already finished its execution stack
I have two angularJS controllers that should be synchronized.
The first is a filter on a list, second displays the list. I have a service user by both controllers and that makes some async ajax-like calls.
My problem is that the filter filters before the list is initialized, so when the page loads for the first time I have unfiltered results. How to solve it?
Here is my JSFiddle
Here is the code:
var myApp = angular.module('myApp', []);
myApp.controller("infoCtrl", function ($scope, $timeout, person) {
person.get().then(function (response) {
// timeout to prevent '$digest already in progress' error
$timeout(function () {
$scope.people = response;
$scope.$apply();
})
});
});
myApp.controller("filterCtrl", function ($scope, person) {
$scope.$watch("maxAge", function (newValue) {
if (newValue) {
person.filterPeople(newValue);
}
});
});
myApp.service("person", function ($q, $timeout) {
var _me = this;
var AjaxGetPeople = function () {
return $timeout(function () {
var somedata = [{name: 'Marcel Sapin',age: 26},
{name: 'Anhel De Niro',age: 42},
{name: 'Johny Resset',age: 30}];
_me.people = somedata;
return somedata;
});
};
var filterPeople = function (maxAge, collection) {
if (!collection) collection = _me.people;
if (!collection) return;
angular.forEach(collection, function (p) {
p.visible = (p.age <= maxAge);
});
};
var get = function () {
if (_me.people) { // return from 'cache'
return $q.resolve(_me.people);
}
// if not 'cached', call 'ajax'
return AjaxGetPeople().then(function (response) {
// add visible property to people
filterPeople(100, response);
_me.people = response;
return response;
});
};
return {
'get': get,
'filterPeople': filterPeople
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="filterCtrl" ng-init="maxAge=30">People younger than
<input ng-model="maxAge" type="number" /> years:
</div>
<hr/>
<div ng-controller="infoCtrl">
<div ng-repeat="person in people" ng-show="person.visible">
{{person.name}}, age {{person.age}}
</div>
</div>
</div>
Anhel De Niro, age 42 should not be displayed when the page is loaded initially, because my filter's max age is 30...
Well, try initialize like this:
var myApp = angular.module('myApp', []);
myApp.controller("infoCtrl", function ($scope, $timeout, person) {
person.get(30).then(function (response) {
// timeout to prevent '$digest already in progress' error
$timeout(function () {
$scope.people = response;
$scope.$apply();
})
});
});
myApp.controller("filterCtrl", function ($scope, person) {
$scope.$watch("maxAge", function (newValue) {
if (newValue) {
person.filterPeople(newValue);
}
});
});
myApp.service("person", function ($q, $timeout) {
var _me = this;
var AjaxGetPeople = function () {
return $timeout(function () {
var somedata = [{name: 'Marcel Sapin',age: 26},
{name: 'Anhel De Niro',age: 42},
{name: 'Johny Resset',age: 30}];
_me.people = somedata;
return somedata;
});
};
var filterPeople = function (maxAge, collection) {
if (!collection) collection = _me.people;
if (!collection) return;
angular.forEach(collection, function (p) {
p.visible = (p.age <= maxAge);
});
};
var get = function (init) {
if (_me.people) { // return from 'cache'
return $q.resolve(_me.people);
}
// if not 'cached', call 'ajax'
return AjaxGetPeople().then(function (response) {
// add visible property to people
filterPeople(init, response);
_me.people = response;
return response;
});
};
return {
'get': get,
'filterPeople': filterPeople
};
});
Its work's in your JSFiddle, hope help you ;D
Following Filter(ageFilter) will filter depending upon maxAge variable
HTML
<div ng-app='myApp' ng-controller="Main" ng-init="maxAge=30">
<input type="text" ng-model="maxAge">
<li ng-repeat="user in users | ageFilter:maxAge">{{user.name}}</li>
</div>
Script
var myApp = angular.module('myApp', []);
myApp.filter('ageFilter', function() {
return function(input, Maxage) {
var out = [];
for (var i = 0; i < input.length; i++){
if(input[i].age <= Maxage)
out.push(input[i]);
}
return out;
};
});
function Main($scope){
$scope.users = [{name: 'Marcel Sapin',age: 26},
{name: 'Anhel De Niro',age: 42},
{name: 'Johny Resset',age: 30}]
}
I'm listing users with:
/api/users/
I'd like to list users who are admins by calling:
/api/users/admins
As trivial as it may seem, I can't find a way to do this.
I do not know which programming language you are using, but I'm going to give you an example using PHP Laravel, and AngularJS.
API
Route::get('/api/users', function ()
{
$users = App\User::all();
return $users;
});
Route::get('/api/users/admin', function ()
{
$users = App\User::where('admin', true)->get();
return $users;
});
FRONT
angular.module('app', [])
.service('api', ['$http', function ($http) {
function getUsers() {
return $http.get('/api/users');
}
function getAdminUsers() {
return $http.get('/api/users/admin');
}
this.getUsers = getUsers;
this.getAdminUsers = getAdminUsers;
}])
.controller('UserCtrl', ['$scope', 'api', function ($scope, api) {
$scope.users = [];
$scope.adminUsers = [];
api.getUsers()
.then(function success(response) {
$scope.users = response.data;
}, function error(response) {
});
api.getAdminUsers()
.then(function success(response) {
$scope.adminUsers = response.data;
}, function error(response) {
});
}]);
Sorry about the lack of details in my question. I was actually asking the question about the angular-restmod module.
Here's what I did in the end:
module.factory('CustomMethods', ['restmod', 'RMUtils', function CustomMethodsMixin(restmod, RMUtils) {
return restmod.mixin(function() {
this.define('Model.$customCollection', function(_url, params) {
var original = this;
return this.$collection(params, {
$urlFor: function() {
return RMUtils.joinUrl(original.$url(), _url);
}
});
});
return this;
});
}]);
And expose all my api to it:
restmodProvider.rebase('CustomMethods')
[plunkr][1]http://plnkr.co/edit/Jk1Rp3nEgUQTmDOs3xBl?p=preview
My current code is structured as below.
angular.module("app",[])
.service("dataService",function($http){
this.get = function (url) {
return $http.get(url);
};
})
.service("mainService",function(dataService){
this.getData = function(pattern){
return dataService.get(pattern+"/abc");
}
})
.controller("mainController",function($scope,mainService){
$scope.refreshData = function(pattern){
loadData(pattern);
}
function loadData(pattern){
mainService.getData(pattern)
.success(function(data){
console.log(data);
})
.error(function(error){
console.log(error);
})
}
})
I have been trying to make sense of how to test it by reading blogs but each blog has either a different approach or the blog is 2-3 years old. I would like to know how do I test the controller?
Should I test each function? If yes, then how should I test the private function? Is using the private function a good idea or should I just add the private function code to the scoped function?
Also is there any better way to do write this function?
Most important part where we are going to create stub:
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
and test that uses it:
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
angular.module("app", [])
.service("dataService", function($http) {
this.get = function(url) {
return $http.get(url);
};
})
.service("mainService", function(dataService) {
this.getData = function(pattern) {
return dataService.get(pattern + "/abc");
}
})
.controller("mainController", function($scope, mainService) {
$scope.refreshData = function(pattern) {
loadData(pattern);
}
function loadData(pattern) {
mainService.getData(pattern)
.success(function(data) {
console.log(data);
}).error(function(error) {
console.log(error);
})
}
})
describe('mainController()', function() {
var scope, controller, mainService, $q;
beforeEach(module('app'));
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
beforeEach(inject(function($controller, $rootScope, _mainService_) {
scope = $rootScope.$new();
controller = $controller('mainController', {
$scope: scope
});
mainService = _mainService_;
}));
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>