I have a select list box, and the I have a button. Based on the button selectId, I have to filter the model which showing in the select list box.
The problem here is that the model only updates when I click this button twice. I have a filter function in GetFormsClicked which have logic regarding this.
My Angular controller is the following:
(function() {
var controllerId = 'GroupsController';
ig.app.controller(controllerId, ['$scope', '$log', '$http', '$compile', 'fileRvwQuestSvc', 'DataSvc',
function($scope, $log, $http, $compile, fileRvwQuestSvc, DataSvc) {
$scope.FrequencyMap = {
1: "Annual",
2: "Monthly",
3: "Half Year"
};
$scope.FormMap = {
1: "CMSMISC",
2: "CMSFPEA",
3: "CMSPIID",
5: "CMSMSR",
7: "CMSCOI"
}
$scope.GetAllGroupForms = function(Id) {
var url = '/GroupForm/Details/' + Id;
$scope.loading = true;
DataSvc.getAjaxData(url)
.then(function(data) {
//success
$scope.GroupForm = data.data;
$scope.GroupFormBack = data.data;
$scope.loading = false;
}, function(httpStatus) {
//failed
$scope.hasErrors = true;
if (httpStatus === 404) {
$scope.errorMessage = "Couldn't retrieve Users Info";
} else {
$scope.errorMessage = 'The system could not process your request, please try again or contact the system administrator.';
}
$log.warn(httpStatus);
$scope.loading = false;
});
};
$scope.availableFormsTestOriginal = [
{
"Id": null,
"GroupId": null,
"FormId": 1,
"SortOrder": null,
"Frequency": 1,
"IsCollapsed": false,
"IsDeleted": false
},
{
"Id": null,
"GroupId": null,
"FormId": 2,
"SortOrder": null,
"Frequency": 1,
"IsCollapsed": false,
"IsDeleted": false
},
{
"Id": null,
"GroupId": null,
"FormId": 3,
"SortOrder": null,
"Frequency": 1,
"IsCollapsed": false,
"IsDeleted": false
}
]
var AddGroupForm = function() {
$scope.loading = true;
var url = '/GroupForm/Create/';
DataSvc.AddFormData(url, $scope.GroupForm)
.then(function(data) {
//success
$scope.loading = false;
//$scope.successMessage = "Form Saved Successfully";
$scope.successMessage = "GroupForm Updated Successfully";
}, function(httpStatus) {
//failed
$scope.hasErrors = true;
if (httpStatus === 404) {
$scope.errorMessage = "Couldn't retrieve Users Info";
} else {
$scope.errorMessage = 'The system could not process your request, please try again or contact the system administrator.';
}
$log.warn(httpStatus);
$scope.loading = false;
});
}
$scope.filterailableforms = function() {
for (i = 0; i < $scope.availableFormsTest.length; i++) {
for (j = 0; j < $scope.GroupForm.length; j++) {
if ($scope.availableFormsTest[i].FormId === $scope.GroupForm[j].FormId && $scope.availableFormsTest[i].Frequency === $scope.GroupForm[j].Frequency) {
$scope.availableFormsTest.splice(i, 1);
}
}
}
}
activate();
$scope.GetFormsClicked = function(selectid) {
$scope.availableFormsTest = angular.copy($scope.availableFormsTestOriginal);
$scope.GetAllGroupForms(selectid);
$scope.updateavailableforms(selectid);
$scope.filterailableforms();
}
function activate() {
$scope.loading = false;
$scope.GetAllGroup();
}
}
]);
})();
My view code is as follows:
<button ng-click="GetFormsClicked(selectedId)">Select Group <span style="color:black"></span></button>` <select size="5" multiple ng-model="available" ng-options="x as FormMap[x.FormId]+' --- '+FrequencyMap[x.Frequency] for x in availableFormsTest" style="width: 400px"></select>
My dataser code:
ig.app.factory('DataSvc', [
'$http', '$q', '$log',
function ($http, $q, $log) {
return {
getAjaxData: function (CtrlUrl) {
var deferred = $q.defer();
var rnd = ((Math.random() * 1000000) + 1);
$http({
method: 'GET',
url: CtrlUrl + "/?r=" + rnd
})
.then(function (data, status, headers, config) {
deferred.resolve(data, status, headers, config);
},
function (data, status, headers, config) {
$log.warn(data, status, headers(), config);
deferred.reject(status);
});
return deferred.promise;
},
AddFormData: function (CtrlUrl, model) {
var deferred = $q.defer();
$http.post(CtrlUrl, model).then(function (data, status, headers, config) {
deferred.resolve(data, status, headers, config);
},function (data, status, headers, config) {
$log.warn(data, status, headers(), config);
deferred.reject(status);
});
return deferred.promise;
},
UpdateFormData: function (CtrlUrl, model) {
var deferred = $q.defer();
$http.post(CtrlUrl, model).then(function (data, status, headers, config) {
deferred.resolve(data, status, headers, config);
},function (data, status, headers, config) {
$log.warn(data, status, headers(), config);
deferred.reject(status);
});
return deferred.promise;
}
}
}]);
Your problem is due to the use of ng-model="variable".
The rule is "always have a dot in your ng-model", you should have a ng-model="obj.variable" with the correct obj.
The reason is that each directive with scope:true inherits the parent scope, and the "variable" you are editing isn't copied back to the parent.
The problem is due to the fact that the strings are copied by value.
By using an object, all the scope will reference the same variable.
Related
We have a requirement on retrieving data from multiple SharePoint lists and creating a joined model to be displayed in the view. We have two lists Employee and Department. Employee list would have field as "Department" which needs to be joined with Department List's Title Field
Below is the controller along with used services, but it is not working as expected.
Employee List data
[
{
"Id": 1,
"Title": "1",
"Name": "ABC",
"Salary": 1000,
"Department": "1",
"ID": 1
},
{
"Id": 2,
"Title": "2",
"Name": "DEF",
"Salary": 600,
"Department": "2",
"ID": 2
},
{
"Id": 3,
"Title": "3",
"Name": "GHI",
"Salary": 500,
"Department": "3",
"ID": 3
}
]
Department List data
[
{
"Id": 1,
"Title": "1",
"Name": "DOC",
"Location": "DIJ",
"ID": 1
},
{
"Id": 2,
"Title": "2",
"Name": "DYU",
"Location": "RTY",
"ID": 2
},
{
"Id": 3,
"Title": "3",
"Name": "UCV",
"Location": "TYU",
"ID": 3
}
]
I am getting some [ngRepeat:dupes] error.
(function () {
angular.module("app")
.controller('homeCtrl', ['$scope', 'employeeService', 'departmentService', function ($scope, employeeService, departmentService) {
var employeevm = {};
var employeesvm = [];
employeeService.getAll()
.then(function (response) {
$scope.employees = response.d.results;
for (var i = 0; i < $scope.employees.length; i++) {
employeevm.Id = $scope.employees[i].Title;
employeevm.Name = $scope.employees[i].Name;
employeevm.Salary = $scope.employees[i].Salary;
departmentService.getItem($scope.employees[i].Department)
.then(function (response) {
$scope.department = response.d.results;
employeevm.DepartmentName = $scope.department[0].Name;
employeevm.Location = $scope.department[0].Location;
employeesvm.push(employeevm);
})
}
$scope.employeesvm = employeesvm;
})
}]);
})();
EmployeeService.js
"use strict";
(function () {
angular.module("app")
.factory("employeeService", ["baseSpServices", function (baseService) {
var listEndPoint = '/_api/web/lists';
var getAll = function () {
var query = listEndPoint + "/GetByTitle('Employee')/Items?$select=ID,Title,Name,Salary,Department";
return baseService.getRequest(query);
};
return {
getAll: getAll,
};
}]);
})();
departmentService.js
"use strict";
(function () {
angular.module("app")
.factory("departmentService", ["baseSpServices", function (baseService) {
var listEndPoint = '/_api/web/lists';
var getItem = function (id) {
var query = listEndPoint + "/GetByTitle('Department')/Items?$select=ID,Title,Name,Location&$filter=Title eq " + id;
return baseService.getRequest(query);
}
return {
getItem: getItem
};
}]);
})();
baseSPService.js
"use strict";
(function () {
angular.module("app")
.factory("baseSpServices", ["$http", "$q", "spContext", function ($http, $q, spContext) {
var baseUrl = _spPageContextInfo.siteAbsoluteUrl;
var getRequest = function (query) {
var deferred = $q.defer();
$http({
url: baseUrl + query,
method: "GET",
headers: {
"accept": "application/json;odata=verbose",
"content-Type": "application/json;odata=verbose"
}
})
.success(function (result) {
deferred.resolve(result);
})
.error(function (result, status) {
deferred.reject(status);
});
return deferred.promise;
};
var postRequest = function (data, url) {
var deferred = $q.defer();
$http({
url: baseUrl + url,
method: "POST",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
"content-Type": "application/json;odata=verbose"
},
data: JSON.stringify(data)
})
.success(function (result) {
deferred.resolve(result);
})
.error(function (result, status) {
deferred.reject(status);
});
return deferred.promise;
};
var updateRequest = function (data, url) {
var deferred = $q.defer();
$http({
url: baseUrl + url,
method: "PATCH",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
"content-Type": "application/json;odata=verbose",
"X-Http-Method": "PATCH",
"If-Match": "*"
},
data: JSON.stringify(data)
})
.success(function (result) {
deferred.resolve(result);
})
.error(function (result, status) {
deferred.reject(status);
});
return deferred.promise;
};
var deleteRequest = function (url) {
var deferred = $q.defer();
$http({
url: baseUrl + url,
method: "DELETE",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
"IF-MATCH": "*"
}
})
.success(function (result) {
deferred.resolve(result);
})
.error(function (result, status) {
deferred.reject(status);
});
return deferred.promise;
};
return {
getRequest: getRequest,
postRequest: postRequest,
updateRequest: updateRequest,
deleteRequest: deleteRequest
};
}]);
})();
You haven't provided much information about what exactly is not working as expected.
Just by viewing your code it looks like your nested then could be the problem. You assign response.d.results to $scope.department, then read values from $scope.department and assign them to properties of employeevm. The problem is that the nested then runs multiple times, so the value assigned to $scope.department is going to change over time.
I'd suggest not assigning anything to $scope.department at all but instead just use the response directly, as follows:
.then(function (response) {
employeevm.DepartmentName = response.d.results[0].Name;
employeevm.Location = response.d.results[0].Location;
employeesvm.push(employeevm);
}
If that's not the problem please provide more information on what's not working.
I have modified my controller as below. I am pretty sure the issue was with handling the promises. Any help on handling error and other performance refinements is very much helpful
(function () {
angular.module("app")
.controller('homeCtrl', ['$filter', '$scope', '$q', 'employeeService', 'departmentService', function ($filter, $scope, $q, employeeService, departmentService) {
var departments = [];
var employeesvm = [];
employeeService.getAll()
.then(function (employees) {
var promises = [];
$scope.employees = employees.d.results;
angular.forEach($scope.employees, function (employee) {
promises.push(departmentService.getItem(employee.Department));
})
$q.all(promises).then(function (responses) {
departments = [];
angular.forEach(responses, function (response) {
departments.push(response.d.results[0]);
})
for (var i = 0; i < $scope.employees.length; i++) {
var employeevm = {};
employeevm.Id = $scope.employees[i].Title;
employeevm.Name = $scope.employees[i].Name;
employeevm.Salary = $scope.employees[i].Salary;
var department = $filter('filter')(departments, { Title: $scope.employees[i].Department });
employeevm.DepartmentName = department[0].Name;
employeevm.Location = department[0].Location;
employeesvm.push(employeevm);
}
$scope.employeesvm = employeesvm;
})
})
}]);
})();
I'm at a loss on this. I have checked the forums and can't seem to find a solution.
I'm working on creating an ionic app to pull json feeds into the app and have them process. I have one feed setup, in one angular module, that is pulling some data perfectly fine. But when I try to create this second module, the feed var it errors, but if I hard code the URL in the $http.get it works fine.
This code errors with TypeError: Cannot read property 'protocol' of undefined:
angular.module('mwre.services', [])
.factory('PropertyFeed', function($http) {
var listings = {
residential: "http://somewebsite/api-access/get/mostwantedrealestate/categories/1?limit=2",
land: "http://somewebsite/api-access/get/mostwantedrealestate/categories/1?limit=2"
};
var content = "http://somewebsite/api-access/get/mostwantedrealestate/properties/"
return {
getPropertiesContent: function(section, successCallback, errorCallback){
$http.get(listings[section])
.success(function(data, status, headers, config) {
successCallback(data);
})
.error(function(data, status, headers, config) {
errorCallback(status);
});
},
getPropertyItem: function(id, successCallback, errorCallback){
$http.get(smalldesc + id)
.success(function(data, status, headers, config) {
successCallback(data);
})
.error(function(data, status, headers, config) {
errorCallback(status);
});
}
}
});
However, making the following change to the $http.get works:
angular.module('mwre.services', [])
.factory('PropertyFeed', function($http) {
var listings = {
residential: "http://somewebsite/api-access/get/mostwantedrealestate/categories/1?limit=2",
land: "http://somewebsite/api-access/get/mostwantedrealestate/categories/1?limit=2"
};
var content = "http://somewebsite/api-access/get/mostwantedrealestate/properties/"
return {
getPropertiesContent: function(section, successCallback, errorCallback){
$http.get("http://somewebsite/api-access/get/mostwantedrealestate/categories/1?limit=2")
.success(function(data, status, headers, config) {
successCallback(data);
})
.error(function(data, status, headers, config) {
errorCallback(status);
});
},
getPropertyItem: function(id, successCallback, errorCallback){
$http.get(smalldesc + id)
.success(function(data, status, headers, config) {
successCallback(data);
})
.error(function(data, status, headers, config) {
errorCallback(status);
});
}
}
});
I can't seem to figure out what I've got wrong in my code.
Here is the controller that is running that feed. It works perfectly fine when the URL is hardcoded.
angular.module('mwre.controllers', [])
.controller('PropertiesCtrl', function($scope, $state, $stateParams, $log, $ionicPopup, PropertyFeed) {
$scope.items = [];
$scope.successGetPropertiesContent = function(data) {
$scope.maxIntro = 100;
$scope.items = data.properties;
for (var i = 0; i < $scope.items.length; i++) {
$scope.items[i].smalldesc = $scope.items[i].smalldesc.replace(/<[^>]+>/gm, '');
if ($scope.items[i].smalldesc.length > $scope.maxIntro) {
$scope.items[i].smalldesc = $scope.items[i].smalldesc.substr(0, $scope.maxIntro) + '...';
}
}
};
$scope.errorGetPropertiesContent = function(status) {
$scope.showAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Error reading property category content',
template: 'Please check your network connection'
});
alertPopup.then(function(res) {
$log.debug('Error reading property category content');
});
};
$scope.showAlert();
};
PropertyFeed.getPropertiesContent($stateParams.propertiesId, $scope.successGetPropertiesContent, $scope.errorGetPropertiesContent);
$scope.goToContent = function(id) {
$state.go('app.properties', { propertiesId: id });
};
})
.controller('PropertyCtrl', function($scope, $state, $stateParams, $log, $ionicPopup, PropertyFeed) {
$scope.item = null;
$scope.successGetPropertyItem = function(data) {
$scope.item = data;
};
$scope.errorGetPropertyItem = function(status) {
$scope.showAlert = function() {
var alertPopup = $ionicPopup.alert({
title: 'Error reading property listing',
template: 'Please check your network connection'
});
alertPopup.then(function(res) {
$log.debug('Error reading property listing');
});
};
$scope.showAlert();
};
PropertyFeed.getPropertyItem($stateParams.propertyId, $scope.successGetPropertyItem, $scope.errorGetPropertyItem);
});
I am filling my template named commentRecipe.html with data.
And i can call controller.add(1,2,'comment here') from inside the template.
The item gets updated in the db and returns my new result.
The Question is: How can i update ex mhRecipeId with the retrieved data.
var app = angular.module('myApp');
app.directive('mhCommentRecipe', ['$log', 'commentService', function ($log, commentService) {
var commentController = function () {
var that = this;
that.add = function (commentId, recipeId, commentText) {
if (recipeId && commentText.length > 0) {
var resultObj = commentService.add(commentId, recipeId, commentText);
}
};
}
return {
restrict: 'A',
templateUrl: '/app/templates/commentRecipe.html',
scope: {
mhRecipeId: '=',
mhCommentId: '=',
mhCommentText: '='
},
controller: commentController,
controllerAs: 'controller'
}
}]);
(function () {
app.factory('commentService', [
'$log', 'httpService', function ($log, httpService) {
var baseEndpointPath = '/myRecipes';
return {
add: function (commentId, recipeId, commentText) {
$log.debug(commentId, 'c');
var data = {
commentId,
recipeId,
commentText
}
var promise = httpService.post(baseEndpointPath + '/comment', data);
promise.then(function (response) {
// added
},
function (error) {
$log.error(error);
});
},
remove: function (commentId) {
if (commentId) {
var data = {
commentId,
recipeId,
commentText
}
data.commentId = commentId;
var promise = httpService.post(baseEndpointPath + '/removeComment', data);
promise.then(function (response) {
$log(response, 'removed response');
},
function (error) {
$log.error(error);
});
}
}
};
}
]);
})();
app.factory('httpService', ['$http', '$q',
function ($http, $q) {
return {
get: function (endpoint) {
var deferred = $q.defer();
$http.get(endpoint)
.success(function (response) {
deferred.resolve(response);
})
.error(function () {
deferred.reject('Failed to fetch response from endpoint');
});
return deferred.promise;
},
post: function (endpoint, data, config) {
var deferred = $q.defer();
$http.post(endpoint, data, config)
.success(function (response) {
deferred.resolve(response);
})
.error(function () {
deferred.reject('Failed to post data to endpoint');
});
return deferred.promise;
},
put: function (endpoint, data, config) {
var deferred = $q.defer();
$http.put(endpoint, data, config)
.success(function (response) {
deferred.resolve(response);
})
.error(function () {
deferred.reject('Failed to put data to endpoint');
});
return deferred.promise;
}
};
}]);
You place the values you want to send to the directive into a variable:
// in controller
that.mhRecipeId = whateverValueHere;
that.mhCommentId = whateverValueHere;
that.mhCommentText = 'comment text';
then on the directive in html you would put:
<mh-comment-recipe mh-recipe-id="controller.mhRecipeId" mh-comment-id="controller.mhCommentId" mh-comment-text="controller.mhCommentText"></mh-comment-recipe>
This will pass the variables into the directive for use.
Unless I misunderstood your question :)
Solved the issue and i am quite embarrassed to tell the solution!
In my view i just used ex: mhRecipeId when i should have used the controllers value.
I wrote a factory to long-poll, with start and stop methods. However, I can't cancel the timer. Any ideas?
app.controller("AuthCtrl", function($scope, $http, $window, User, Poller) {
Poller.start(1, $scope.session.user.user_uuid, function(result) {
User.data.queues.montage_progress = result.field;
if (result.field == 100) {
Poller.stop(); //DOES NOT STOP (see below)
}
});
})
Here is the factory:
app.factory('Poller', function($http, $q, $interval, $window) {
var poll = this;
poll.timer = null;
poll.checkProgress = function(field, user_uuid) {
var deferred = $q.defer();
$http({
method: 'GET',
url: '/api/v1/poll/',
json: true,
params: {
field: field,
user_uuid: user_uuid
}
})
.success(function(data) {
deferred.resolve(data);
}).error(function() {
deferred.reject("Error checking poll");
});
return deferred.promise;
};
poll.start = function(url, user_uuid, callback) {
poll.timer = $interval(function() {
poll.checkProgress(url, user_uuid).then(function(result) {
console.log(result);
callback(result);
}, function(error) {
alert(error);
});
}, 2000);
};
poll.stop = function() {
$interval.cancel(poll.timer);
};
return poll;
});
EDIT:
Changed $window.clearInterval to $interval.cancel(poll.timer); as suggested below. But still can't cancel polling...
You should use the cancel method of $interval, not clearInterval
poll.stop = function() {
$interval.cancel(poll.timer):
};
So i'm busy with a webapplication and i'm stuck now with parsing an object. What I just tried to do is getting the ID of all results but it gives me undefined back in my console.
What did i try:
var app = angular.module("DB", []);
app.controller("Controller", function($scope, $http) {
$http.defaults.headers.common["Accept"] = "application/json";
$http.get('api_url').
success(function(data, status, headers, config) {
$scope.games = data.results;
$scope.id = data.results.id;
//Do i need a foreach here because it doesn't loop through all records and it gives me undefined.
$http.get('http:/api/id/' + $scope.id + '?api_key=', function(e){
}).
success(function(data, status, headers, config) {
$scope.details = data;
console.log(data);
//this returns the complete JSON
});
}).
error(function(data, status, headers, config) {
//handle errors
});
});
the first http.get loops through a JSON like:
"results": [
{
"easy": false,
"id": 1,
"title": "title",
},
{
"easy": false,
"id": 2,
"title": "title",
},
{
"easy": true,
"id": 2,
"title": "title",
}
]
and what the second on needs to do is get all of the ID's from the JSON and start a new GET:
$http.get('http:/api/id/' + $scope.id + '?api_key=', function(e){
}).
success(function(data, status, headers, config) {
$scope.details = data;
console.log(data.data);
});
})
the problem is that is, is that $scope.id = data.results.id; is returing nothing, do i need a foreach or something to loop through it all?
And displaying it i did try:
<div ng-repeat="detail in details">
{{ detail }}
{{ detail.adult }}
</div>
but is does not display anything (fyi i changed $scope.id = data.results.id; to $scope.id = data.results[0].id; to test it)
the JSON for the second GET looks like:
{
"adult": false,
"collection": {
"id": 131295,
"name": "Collection",
},
"levels": [{
"id": 28
}, {
"id": 12
}, {
"id": 878
}],
"homepage": "google",
"id": 100402,
"overview": "lorem ipsum"
}
i can't access the object with {{ detail.adult }} for example.
The reason why data.results.id is returning nothing is because data.results is an Array of objects. If what you want is an Array with the IDs of the objects of data.results you could do it like this:
var resultIDs = data.results.map(function(result){return result.id;});
I'm not sure, but I think that this is what you want:
var app = angular.module("DB", []);
app.controller("Controller", function($scope, $http) {
$scope.details = [];
$http.defaults.headers.common["Accept"] = "application/json";
$http.get('api_url').
success(function(data, status, headers, config) {
$scope.games = data.results;
for(var i =0;i<$scope.games.lenght;i++){
$http.get('http:/api/id/' + $scope.games[i].id + '?api_key=', function(e){
}).
success(function(data, status, headers, config) {
$scope.details.push(data);
});
}
}).
error(function(data, status, headers, config) {
//handle errors
});
});
However I would check if the API that you are using has a method that accepts an array of IDs instead of a single ID, so that you don't have to iterate like that.
If this API is a RESTful service you could do it without iterating, like this:
var app = angular.module("DB", []);
app.controller("Controller", function($scope, $http) {
$scope.details = [];
$http.defaults.headers.common["Accept"] = "application/json";
$http.get('api_url').
success(function(data, status, headers, config) {
$scope.games = data.results;
var resultIDs = data.results.map(function(result){return result.id;});
$http.get('http:/api?id=' + resultIDs.join(',') + '?api_key=', function(e){
}).
success(function(data, status, headers, config) {
$scope.details = data;
});
}).
error(function(data, status, headers, config) {
//handle errors
});
});