I'm trying to loop through "tabs" in the Json object using AngularJS? How can I do it?
var model = {
"$id": "1",
"tabs": [{
"$id": "2",
"id": 2,
"name": "Output",
"layoutId": 1,
"order": 1,
"dashboardId": 1
}, {
"$id": "15",
"id": 3,
"name": "Yield",
"layoutId": 1,
"order": 2,
"dashboardId": 1
}, {
"$id": "24",
"id": 4,
"name": "Trend",
"layoutId": 1,
"order": 3,
"dashboardId": 1
}],
"id": 1,
"name": "Test",
"title": "Test",
"description": "Test Dashboard",
"createDate": "2015-06-08T00:00:00+01:00",
"ownerId": 1,
"enabled": true
};
When I try this, I get "undefined" in the console.
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
not sure what I'm doing wrong?
EDIT:
The data is coming from ASP.Net controller:
$http.get("/Dashboards/GetDashboardData").success(function (data) {
model = data;
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
}).error(function (data) {
console.log("error");
});
I expect that the model is not ready at the time you loop though it. Run the following code with your inspector open - the code you have is correct, but in your case fails because model isn't ready when you run the loop.
If you're loading data asyncronously you'll want to wait until the data is returned, either using a promise or a callback, and the loop through it.
var model = {
"tabs": [{
"name": "Output",
}, {
"name": "Yield",
}, {
"name": "Trend",
}],
};
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Ok I found the answer. It looks like my controller returns Json object as a string, so I have to switch it to object before I can use it as an object.
I have add this line before using model in the loop:
model = JSON.parse(data);
The whole solution with promise (not sure if I need it now):
DataService.getDashboardData().then(function (data) {
model = JSON.parse(data);
angular.forEach(model.tabs, function (tab) {
console.log(tab);
});
});
app.service("DataService", ["$http", "$q", function ($http, $q) {
return {
getDashboardData: function () {
var dfd = $q.defer();
$http.get('/Dashboards/GetDashboardData').success(function (result) {
dfd.resolve(result);
});
return dfd.promise;
}
};
}]);
Related
I have been playing around with the Angular UI Tree drag and drop and have come by an issue that has stumped me. The json is being received from my services. When it is received by my controller, I must format it properly with an empty array so it will be able to hold childen:
Formatting:
function categorySuccessPost(data) {
var emptyCategoryArray = {
Categories: []
}
for (var i = 0; i < data.length; i++) {
$.extend(data[i], emptyCategoryArray);
}
$scope.categoryData = data;
}
It is now formatted and looks like:
[ { "CategoryId": 27054, "MerchantId": 5594, "ProductCategoryId": 1310,
"Name": "BulkUpload", "Description": "BulkUpload", "DateCreated":
"/Date(1446793200000-0000)/", "IsActive": true, "IsDefault": false, "ItemCount":
5, "ResponseStatus": { "ErrorCode": "SUCCESS" }, "TotalRecordCount": 15,
"Categories": [] }, { "CategoryId": 23267, "MerchantId": 5594,
"ProductCategoryId": 818, "Name": "Coupon", "Description": "Coupon",
"DateCreated": "/Date(-62135596800000-0000)/", "IsActive": true, "IsDefault":
true, "ItemCount": 1, "ResponseStatus": { "ErrorCode": "SUCCESS" },
"TotalRecordCount": 15, "Categories": [] } }
I have tried two different functions when attempting to add a child:
Function 1 (Uses model value):
$scope.newSubItem = function (scope) {
var currentCategoryData = scope.$modelValue;
currentCategoryData.Categories.push({
CategoryId: currentCategoryData.CategoryId * 10 + currentCategoryData.Categories.length,
Name: currentCategoryData.Name + '.' + (currentCategoryData.Categories.length + 1),
Categories: []
});
};
Function 2 (Uses index of object in the array, and yes, I have made sure the correct index is being passed):
$scope.newSubItem = function (index) {
var array = $scope.categoryData;
array[index].Categories.push({
CategoryId: 12312,
Name: 'test',
Categories: []
});
};
The issue is that instead of pushing the new data to the selected index, it adds the json to every Categories :
[ { "CategoryId": 27054, "MerchantId": 5594, "ProductCategoryId": 1310,
"Name": "BulkUpload", "Description": "BulkUpload", "DateCreated":
"/Date(1446793200000-0000)/", "IsActive": true, "IsDefault": false, "ItemCount":
5, "ResponseStatus": { "ErrorCode": "SUCCESS" }, "TotalRecordCount": 15,
"Categories": [ { "CategoryId": 12312, "Name": "test", "Categories": [] } ] }, {
"CategoryId": 23267, "MerchantId": 5594, "ProductCategoryId": 818, "Name": "Coupon", "Description": "Coupon", "DateCreated": "/Date(-62135596800000-
0000)/", "IsActive": true, "IsDefault": true, "ItemCount": 1, "ResponseStatus":
{ "ErrorCode": "SUCCESS" }, "TotalRecordCount": 15, "Categories": [ {
"CategoryId": 12312, "Name": "test", "Categories": [] } ] }
I am not showing the HTML because it does not appear to be an issue. Here's where I have narrowed it down to, but still have no explanation:
If I use the data that goes through the $.extend method then it adds a child to every parent. But if I copy the json that is generated after the formatting, put it into and object and then read from that, then it only adds a child to the selected parent like I want. But it is necessary to add the empty array. Any idea why this is happening and any solution?
EDIT
One more piece of information that may be important: When I add a full Category (different function), rather than adding a subcategory and then try to add a child to the newly generated category then it works correctly (adding only a child to that category):
$scope.addCategory = function () {
var name = $scope.categoryName;
// Temporary
var categoryId = Math.floor((Math.random() * 50000) + 1)
console.log(name, categoryId)
$scope.categoryData.unshift({ CategoryId: categoryId, Name: name, Categories: [] })
$scope.categoryName = "";
$("#addCategoryModal").modal('hide');
Notification.success({ message: 'Category Added Successfully!', delay: 3000 });
}
I'm still not sure exactly why this is happening, but this was my solution to fixing the issue:
Remove the $.extend for loop and $.extend function:
function categorySuccessPost(data) {
$scope.categoryData = data;
}
When adding an item, check if the array has been initialized, if not, create it in the current scope:
$scope.newSubItem = function (scope) {
var currentCategoryData = scope.$modelValue;
if(currentCategoryData.Categories === 'undefined'){
currentCategoryData.Categories = [];
}
currentCategoryData.Categories.push({
CategoryId: currentCategoryData.CategoryId * 10 + currentCategoryData.Categories.length,
Name: currentCategoryData.Name + '.' + (currentCategoryData.Categories.length + 1),
Categories: []
});
};
The issue with this method is that you can no longer drag a node into an empty parent.
Am trying to call Angularjs function outside the controller component like the below :
<script type="text/javascript">
function saveprof() {
$('.spinner').show();
$.ajax({
type: "POST",
url: "saveprof",
enctype: 'multipart/form-data',
async: true,
data: {
'rinput_Aj': JSON.stringify(angular.element(document.getElementById('rdExampleApp')).scope().$func()),
'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken]").val()
},
success: function (data, textStatus, jqXHR) {
$('#message').html(data);
window.location.href = 'myprofile';
window.location('myprofile');
$('.spinner').fadeOut();
}
});
}
</script>
Here is the angularjs controller code :
<script>
var app = angular.module('rdExampleApp', ['ui.rdplot']);
app.controller('rdPlotCtrl', function ($scope) {
$scope.dataset = {
"d0": { "id": 0, "name": "Housing", "value": 18 },
"d1": { "id": 1, "name": "Travel", "value": 31.08 },
"d2": { "id": 2, "name": "Restaurant", "value": 64 },
"d3": { "id": 3, "name": "Bank", "value": 3 },
"d4": { "id": 4, "name": "Movies", "value": 10 }
};
$scope.func = function func() {
var jdata = $scope.dataset;
return jdata;
}
});
</script>
It throws an error
Uncaught TypeError: Cannot read property '$func' of undefined
EDIT:
After the suggestions, I converted my jquery ajax call to $http function in Angularjs.. But it does nothing.. No error in console :(
Here is how am invoking the $http service function
<body ng-controller="rdCtrl">
<a ng-click="saveprof()">Save</a>
<script>
var app = angular.module('rdExampleApp', ['ui.rdplot']);
app.controller('rdCtrl', function ($scope) {
$scope.dataset = {
"d0": { "id": 0, "name": "Housing", "value": 18 },
"d1": { "id": 1, "name": "Travel", "value": 31.08 },
"d2": { "id": 2, "name": "Restaurant", "value": 64 },
"d3": { "id": 3, "name": "Bank", "value": 3 },
"d4": { "id": 4, "name": "Movies", "value": 10 }
};
$scope.func = function func() {
var jdata = $scope.dataset;
return jdata;
}, function ($scope, $http) {
$scope.saveprof = function () {
//show spinner
$('.spinner').show();
$http.post('saveprof', {
data: { 'data': JSON.stringify($scope.dataset) }
})
.success(function (data) {
if (data == "null") {
//your code if return data empty
} else {
//your code if return data not empty
$('#message').html(data);
}
//hide spinner
$('.spinner').fadeOut();
})
.error(function (data, status, headers, config) {
console.log('error' + status);
//hide spinner in case of error
$('.spinner').fadeOut();
})
}
}
);
</script>
</body>
What am I missing?
in order to run XMLHttpRequest requests to the server you have many options in angularjs, you dont have to mess with simple javascript and call angular scope to get variables and functions.
you can do that either with $http or with services(leave it for now).
i am going to show how you can make the request with $http in native angular.
first of all you have to import the $http module on the declaration of your controller, like this :
var app = angular.module('rdExampleApp', ['ui.rdplot']);
app.controller('rdPlotCtrl', function ($scope,$http) {...});
into you controller you create the json object as you do it and then do the request like this:
//show spinner
$('.spinner').show();
$http.post('dal/addEventHalls.php', {
data: {'data': $scope.datase}
})
.success(function (data) {
if (data == "null") {
//your code if return data empty
} else {
//your code if return data not empty
}
//hide spinner
$('.spinner').fadeOut();
})
.error(function (data, status, headers, config) {
console.log('error' + status);
//hide spinner in case of error
$('.spinner').fadeOut();
})
as you can see we dont use url parameter but we pass the url directly into post() function. the data parameter is there to put whatever data you would like to send to the server.
hope helps good luck.
UPDATE
personally i dont stringify the data parameters.i pass them like json object
into php file , in order to get the data , try this:
$params = json_decode(file_get_contents('php://input'), true); //read values from angular factory-service
I'm having trouble getting two JSON APIs on a website to merge into a single array rather than two.
My two JSON strings look like this:
{
"users": [
{
"name": "test1",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test2",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test3",
"uniqueid": "randomlygeneratedUUID"
}
}
{
"users": [
{
"name": "test4",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test5",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test6",
"uniqueid": "randomlygeneratedUUID"
}
}
and using something like Request, I grab the two URLs (the code looks like this):
var RequestMultiple = function (urls, callback) {
'use strict';
var results = {}, t = urls.length, c = 0,
handler = function (error, response, body) {
var url = response.request.uri.href;
results[url] = { error: error, response: response, body: body };
if (++c === urls.length) { callback(results); }
};
while (t--) { request(urls[t], handler); }
};
var DoRequest = function() {
var urls = ["url1", "url2"];
RequestMultiple(urls, function(responses) {
for (url in responses) {
response = responses[url];
if (response.body){
var JsonBody1 = JSON.parse(response[urls[0]]);
var JsonBody2 = JSON.parse(response[urls[1]]);
var MergeJsonBody = JsonBody1.concat(JsonBody2);
console.log(JSON.stringify(MergeJsonBody).toString());
} else {
console.log('Url', url, response.error);
}
}
});
});
console.log(DoRequest());
The issue I'm having is it doesn't merge, but when it does it looks like this:
{"users": [{ "name": "test1","uniqueid": "randomlygeneratedUUID"},{ "name": "test2","uniqueid": "randomlygeneratedUUID"},{ "name": "test3","uniqueid": "randomlygeneratedUUID"}} unidentified {"users": [{ "name": "test4","uniqueid": "randomlygeneratedUUID"},{ "name": "test5","uniqueid": "randomlygeneratedUUID"},{ "name": "test6","uniqueid": "randomlygeneratedUUID"}}
And it returns an error about the string unidentified.
When I don't get that error, it only shows the second JSON body.
What am I doing wrong? And is there a module or a best in practice way to do this?
EDIT:
Okay I took the solution provided, and I still hit a wall. To counter the issues I basically just had two unique requests that add to a local array variable, then once the command was triggered, create the array, then erase all the items from the array and start all over again. Thanks for all the help!
First of all both of your JSONs are missing closing square brackets. I guess its typo but below is the correct JSON.
{
"users": [
{
"name": "test4",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test5",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test6",
"uniqueid": "randomlygeneratedUUID"
}
]
}
Now change below line of code
JsonBody1.concat(JsonBody2);
to
JsonBody1.users.concat(JsonBody2.users);
This will should give you expected results. You are doing concat on the actual objects instead of arrays.
I want to combine multiple json data into a single vm. I read that you can map from js into the model multiple times and it should be merging but on my case, it's not. It's replacing the data.
function Item(ID, Name, Description) {
this.ID = ko.observable(ID);
this.Name = ko.observable(Name);
this.Description = ko.observable(Description);
}
var MasterViewModel = {
model: ko.observableArray([])
};
$.getJSON(url, function (response) {
ko.mapping.fromJS(response["TM1.Cube"], Item, MasterViewModel.model);
ko.mapping.fromJS(response["TM1.Dimension"], Item, MasterViewModel.model);
})
ko.applyBindings(MasterViewModel);
And here is my json data
{
"LogicalName": "TM1.Model",
"ID": "12345",
"Name: "Sample",
"TM1.Cube": [
{
"LogicalName": "TM1.Cube",
"ID": "111111",
"Name": Assets"
},
{
"LogicalName": "TM1.Cube",
"ID": "111112",
"Name": Finance"
}
],
"TM1.Dimension": [
{
"LogicalName": "TM1.Dimension",
"ID": "222221",
"Name": Assets"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222222",
"Name": Finance"
}
]
}
and the outcome I expected is like this
{
"LogicalName": "TM1.Cube",
"ID": "111111",
"Name": Assets"
},
{
"LogicalName": "TM1.Cube",
"ID": "111112",
"Name": Finance"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222221",
"Name": KPI"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222222",
"Name": Default"
}
I have added a jsFiddle http://jsfiddle.net/e1ppj3qc/1/
The mapping plugin can take an existing model but I don't believe it will merge data.
For example you could map twice like so:
{one: "yo"}
and
{two: "dawg"}
into the same model and you would now have two observables, one() and two()
But if you was to do this (which you are):
{one: ["yo"]}
and
{one: ["dawg"]}
it will always overwrite the matched properties.
You could instead do the mapping and then simply push into the array that you want to add to like so:
function pushCubs(dataToPush) {
ko.utils.arrayPushAll(MasterViewModel.modelcub, dataToPush());
}
pushCubs(ko.mapping.fromJS(data));
pushCubs(ko.mapping.fromJS(data2));
http://jsfiddle.net/e1ppj3qc/2/
Imagine the following JSON API:
[
{
"id": "1",
"name": "Super Cateogry",
"products": [
{
"id": "20",
"name": "Teste Product 1"
},
{
"id": "21",
"name": "Teste Product 2"
},
{
"id": "22",
"name": "Teste Product 3"
}
]
}
]
Is there anyway for me to only return the products array with Angularjs?
I have a simple service calling the JSON:
services.factory("ProductService", function($http) {
return {
"getProducts": function() {
return $http.get("/product/index");
}
};
});
That is being called in the controller like so:
components.success(function(data) {
$scope.products = data;
});
But it returns the whole JSON as expected, I need it to return only the "products" array so I can iterate through it.
PS: This is merely a simple example to illustrate the problem, I realize that I could change the API to fit my needs in this case, but that's not the point.
You would just assign the products array to your scope property...
components.success(function(data) {
$scope.products = data[0].products;
});
You could customize it via a promise, and do it yourself.
"getProducts": function() {
var promise = $q.defer();
$http.get("/product/index").success(function(data){
promise.resolve(data && data.products);
}).error(function(msg){
promise.reject(msg);
})
return promise.promise;
}
How to use:
getProducts().then(
function(data) {
$scope.products = data;
},
function(msg){
alert('error')
}
);