How to get deeper in a JSON object using angularJS? - json

I am using AngularJs to get some information inside this JSON object, specifically the author's first and last name:
{
"bookid": "1",
"title": "Spring In Action",
"publisher": "Manning Publications Co.",
"isbn": "978-1-935182-35-1",
"owner": "Catalyst IT Services",
"publishyear": "2011",
"image": "C:/imagefolder/spring-in-action.jpg",
"description": "Totally revised for Spring 3.0, this book is a...",
"author": [
{
"authorid": "1",
"firstname": "Craig",
"lastname": "Walls",
"description": "Craig Walls has been professionally developing software for over 17 years (and longer than that for the pure geekiness of it). He is the author of Modular Java (published by Pragmatic Bookshelf) and Spring in Action and XDoclet in Action (both published by (...)"
}
],
"media": [
],
"tags": [
{
"tagid": "1",
"tagname": "Java"
},
{
"tagid": "5",
"tagname": "Spring"
}
],
"copies": [
{
"bookcopyid": "2",
"location": "Beaverton",
"status": "available"
}
]
}
The code I have right now is (which was provided by bosco2010 in this plunker (http://plnkr.co/edit/GbTfJ9)):
var app = angular.module('app', []);
app.factory('JsonSvc', function ($http) {
return {read: function(jsonURL, scope) {
return $http.get(jsonURL).success(function (data, status) {
scope.data = data.author;
});
}};
});
app.controller('MainCtrl', function($scope, JsonSvc) {
JsonSvc.read('data.json', $scope).then(function () {
$scope.nestedObj = $scope.data;
});
$scope.name = "world";
});

To get the first and last name, you'll need to reference author[0].firstname and author[0].lastname.

var app = angular.module('app', []);
app.factory('JsonSvc', function ($http) {
return {read: function(jsonURL) {
return $http.get(jsonURL);
}};
});
app.controller('MainCtrl', function($scope, JsonSvc) {
// The return object from $http.get is a promise. I used .then()
// to declare $scope.nestedObj after the http call has finished.
JsonSvc.read('data.json').then(function (data) {
console.log(data.data);
$scope.nestedObj = data.data.level1;
});
// ensure app is working
$scope.name = "world";
// Using nested obj within declared scope var doesn't work
// Uncomment below to break whole app
// Using nested obj in a function works but throws TypeError
// Declaring $scope.data.level1.level2 = [] first helps here
$scope.getLen = function () {
return $scope.nestedObj ? $scope.nestedObj.level2.length : ''; // return an empty string if the callback didn't happen yet
};
});
In short, it is incorrect to use both the success() function and also the then() function of the promise returned by the $htttp service.
Moreover, it is wrong to pass your scope as a parameter to your service and try to modify it there.
if you need to communicate between the service and a controller directly, you can use either $rootScope, $broadcat, or both.
I patched up your code, and now it works.
Plunk:
http://plnkr.co/edit/PlJZZn?p=preview

Related

How to create a custom intent and calling helper intent using Actionsdk?

Please find my action.json file content
{
"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "testapp"
},
"intent": {
"name": "actions.intent.MAIN",
"trigger": {
"queryPatterns": [
"talk to Developer"
]
}
}
},
{
"name": "BUY",
"intent": {
"name": "com.example.sekai.BUY",
"parameters": [{
"name": "color",
"type": "SchemaOrg_Color"
}],
"trigger": {
"queryPatterns": [
"find some $SchemaOrg_Color:color sneakers",
"buy some blue suede shoes",
"get running shoes"
]
}
},
"fulfillment": {
"conversationName": "testapp"
}
}
],
"conversations": {
"testapp": {
"name": "testapp",
"url": "https://us-central1-samplejs2-id.cloudfunctions.net/testApp",
"fulfillmentApiVersion": 2,
"inDialogIntents": [
{
"name": "actions.intent.CANCEL"
}
]
}
},
"locale": "en"
}
Please find my index.js file content
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {actionssdk} = require('actions-on-google');
const app = actionssdk({debug: true});
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
app.intent('com.example.sekai.BUY', (conv, input) => {
console.log("Inside custom intent");
conv.ask('<speak>Hi! <break time="1"/> ' +
' The color you typed is' +
`<say-as >${input}</say-as>.</speak>`);
});
app.intent('actions.intent.MAIN', (conv, input) => {
conv.ask('<speak>Hi! <break time="1"/> ' +
'You are entering into samplejs application by typing ' +
`<say-as >${input}</say-as>.</speak>`);
});
app.intent('actions.intent.CANCEL', (conv) => {
conv.close(`Okay, let's try this again later.`);
});
app.intent('actions.intent.TEXT', (conv, input) => {
if (input === 'bye') {
return conv.close('Goodbye!');
}
conv.ask('<speak>You said, ' +
`<say-as >${input}</say-as>.</speak>`);
});
//exports.app = app;
console.log("global----------->",global);
exports.testApp = functions.https.onRequest(app);
Whenever I call the custom intent "BUY" using any color, instead of calling my custom intent it is calling "intent.Text". How to fix this issue?
While creating cloud function I have select JavaScript option.
For creating a custom intent, is these much updates is need in action.json?
Is there any option for creating custom intent?
How to call this helper content in the js file?
app.intent('ask_for_place', (conv) => {
conv.ask(new Place(options));
});
Custom intents are only triggered as welcome intents for "deep linking". Once the conversation has started, all conversational intents will be reported as TEXT.
So for the intent com.example.sekai.BUY you defined in your actions.json file, and if your Action was named something like "super store", then the following invocation would trigger that intent:
Hey Google, ask super store to find some blue sneakers
but once the conversation had started, asking "find some blue sneakers" would trigger a TEXT intent.
The Actions SDK with actions.json is primarily intended for use by systems that provide the natural language processing and just want to get the text after it has been converted from speech.
If you want more sophisticated natural language processing, where each phrase in the conversation will trigger a user-defined Intent, take a look at Dialogflow.

AngularJS $scope is undefined outside of .then function

I have a a form which includes select input but the thing is ng-options is not working
Select code
<select ng-model="selectedGender" ng-options="item.value for item in genderData">
I got the data from
ReferenceService.searchCategory("GENDER").then(function (response){
$scope.genderData = response.data;
console.log($scope.genderData);
})
This is the console.log($scope.genderData)
Array(2)
0:{referenceId: 1, category: "GENDER", key: "GENDER_KEY", value: "Male", $$hashKey: "object:3"}
1:{referenceId: 2, category: "GENDER", key: "GENDER_KEY", value: "Female", $$hashKey: "object:4"}
length:2
__proto__
:
Array(0)
but I have tried hard coding the data
$scope.genderData= [
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
];
and it worked! but I used ng-options="item.name for item in genderData">
btw don't mind the data I just searched it for fast use
EDIT:
I think I found the problem. Why is it undefined outside the function?
check this console
line 244 is undefined but line 242 is not?
store the response in var then out side the function assign that var to $scope. it is a callback issue.
If still it's showing same you can use localsorage to store and get the data. but this approach is not recomanded in angularjs. but if nothing happen then you can use this approcah also
That's because ReferenceService.searchCategory("GENDER") returns a promise.
A promise will wait until the data is resolved, and then move on to its success function callback. Which is the .then(function(response)).
So the code will get to the console.log on line 244 before the promise has finished, and $scope.genderData has been created and therefore is undefined
The console.log on line 242 will wait until the promise has been resolved, and calls the success callback function.
UPDATE:
Here an example how to correctly link the $scope to the factory.
Note that you must link to the object and not to its properties in your $scope.
Wrong:
$scope.gender = ReferenceService.data.genderData;
Correct:
$scope.gender = ReferenceService.data;
Example:
myApp.factory('ReferenceService',
function ()
{
var ReferenceService = {
// This is the global object. Link the $scope to this object
data: {
genderData: {}
},
searchCategory: function (type)
{
var getData = $http.get("URL", { params: { gender: type } }).then(
function (response)
{
// Store the data in the factory instead of the controller
// You can now link your controller to the ReferenceService.data
ReferenceService.data.genderData = response.data;
}
)
return getData;
}
}
return ReferenceService;
}
);
myApp.controller('MyController',
function ($scope, ReferenceService)
{
// Link $scope to data factory object
$scope.gender = ReferenceService.data;
// Now you only have to call the factory function
ReferenceService.searchCategory("GENDER");
// This will now log the correct data
console.log($scope.gender.genderData);
}
)

Im trying to get values of the following JSON object and display them in html using angularness

In the following JSON object, I'm trying to get the value of the streets
Get business profile data :
{
"_id": "56dd1bd4d0561b403f683bfd",
"UserId": "56b301516b9064189049acb5",
"WebURL": "2",
"PhoneNumber": "3",
"ContactEmail": "1#gmail.com",
"AdditionalInfo": "",
"__v": 0,
"DateCreated": "2016-03-07T06:12:36.957Z",
"Categories": [],
"Addresses": [{
"Street": "1",
"City": "1",
"State": "1",
"Country": "1",
"SuiteNumber": "1",
"_id": "56dd1bd4d0561b403f683bfe"
}]
}
So far this is what I have:
Info.GetData()
.success(function (response){
$scope.Data = response;
})
.error(function (response, status) {
alert("Can Not Retrieve Company Info, Please Contact Admin")
})
<div ng-repeat="x in Data.Addresses">
{{x.Street}}
</div>
I still can't get it working.
Assuming your Info.GetData() is making a $http call and you are using success instead of then, you will still have to use then wherever there is a promise. If you are doing this
return
angular.module('app').factory('Info', function($http) {
return {
getData: function() {
return $http.get('url');
};
};
});
in your Info.getData(). You could instead do
return
angular.module('app').factory('Info', function($http) {
return {
getData: function() {
return $http.get('url').then(function(response)
{
return response.data;
}
};
};
});`
Also, you need to check if your service is returning a promise. If its a promise you should resolve it. You can't assume that your promise has a .success().

Use JSON data coming from WebApi in AngularJS application

I get some data from a WebApi, the answer (below the code to get the datas) is in JSON. But I can't access this result from angularJS. The datas look like :
{
"$id": "1",
"result": [
{
"$id": "2",
"name": "Français",
"code": "FR",
"id": 1
},
{
"$id": "3",
"name": "Néerlandais",
"code": "NL",
"id": 2
},
{
"$id": "4",
"name": "English",
"code": "EN",
"id": 3
}
]
}
But I get the error below when I try to display the result :
data.result is undefined
I get the data like this :
(function () {
angular.module('myApp')
.factory('dataService', ['$q', '$http', dataService]);
function dataService($q, $http) {
return {
initFormCustomer: initFormCustomer
};
function initFormCustomer() {
return $http({
method: 'GET',
url: 'http://localhost:123456/api/forminit/customer/',
headers: {
},
transformResponse: transformCustomer,
cache: true
})
.then(sendResponseData)
.catch(sendGetCustomerError)
}
function sendResponseData(response) {
return response.data;
}
function transformCustomer(data, headersGetter) {
var transformed = angular.fromJson(data.result);
console.log(data.result[0]);
return transformed;
}
function sendGetCustomerError(response) {
return $q.reject('Error retrieving customer(s). (HTTP status: ' + response.status + ')');
}
}
}());
The controller :
(function () {
angular.module('myApp')
.controller('customerController', ['$location', '$scope', 'dataService', CustomerController]);
function CustomerController($location, $scope, dataService) {
var vm = this;
vm.languages = dataService.initFormCustomer();
}
}());
I think the transform function gets a json string that you have to deserialize before using it as an object... try sth like:
function transformCustomer(data, headersGetter) {
var transformed = angular.fromJson(data);
console.log(transformed.result[0]);
return transformed.result;
}
Additionally you may look at the docs https://docs.angularjs.org/api/ng/service/$http . There is some code showing how to append a transform to the default one (that do the deserialization and XSRF checks)

How do I customize knockout mapping creation in nested model?

Completely new to Knockout and I am trying to map a JSON response from the server to specific models using the knockout mapping plugin. The models are nested and I'm trying to override object construction using the create callback even in the nested models. However, it doesn't appear that my mapping options are being read properly. Example JSON:
{
"EmployeeFeedbackRequestSubmissions": [
{
"EmployeeFeedbackRequestSubmissionId": 0,
"Employee": "John Smith0",
"EmployeesWorkedWith": [
{
"EmployeeName": "Joe Smith",
"ProjectsWorked": [
{
"ProjectName": "Document Management Console"
},
{
"ProjectName": "Performance Eval Automation"
},
{
"ProjectName": "Business Tax Extensions"
}
]
},
{
"EmployeeName": "Michael Jones",
"ProjectsWorked": [
{
"ProjectName": "Document Management Console"
},
{
"ProjectName": "Performance Eval Automation"
},
{
"ProjectName": "Business Tax Extensions"
}
]
},
{
"EmployeeName": "Jason Smith",
"ProjectsWorked": [
{
"ProjectName": "Document Management Console"
},
{
"ProjectName": "Performance Eval Automation"
},
{
"ProjectName": "Business Tax Extensions"
}
]
},
{
"EmployeeName": "Robert Will",
"ProjectsWorked": [
{
"ProjectName": "Document Management Console"
},
{
"ProjectName": "Performance Eval Automation"
},
{
"ProjectName": "Business Tax Extensions"
}
]
}
]
}
// more EmployeeFeedbackRequestSubmissions
]
}
Mapping options:
var mappingOptions = {
// overriding default creation/initialization code
'EmployeeFeedbackRequestSubmissions': {
create: function (options) {
return (new(function () {
this.EmployeeHeading = ko.computed(function () {
return "Performance Evaluation Employee: " + this.Employee();
}, this);
ko.mapping.fromJS(options.data, {}, this);
})());
},
'EmployeesWorkedWith': {
create: function (options) {
return new instance.EmployeesWorkedWithModel(options.data);
}
}
}
};
Sample fiddle with full example: http://jsfiddle.net/jeades/9ejJq/2/
The result should be the ability to use the computed nameUpper from the EmployeesWorkedWithModel. I'm also open to suggestions about a better way to do this as this may not be the best way to handle this.
You were almost there. Straight to it working: http://jsfiddle.net/jiggle/na93A/
The mappings options object doesn't need to be nested, the mapping plug in will look up the mapping from the name, when you pass them to ko.mapping.fromJSON
So your mapping options object should be single level:
var self = this;
self.mappingOptions = {
// overriding default creation/initialization code
'EmployeeFeedbackRequestSubmissions': {
create: function (options) {
return (new(function () {
this.EmployeeHeading = ko.computed(function () {
return "Performance Evaluation Employee: " + this.Employee();
}, this);
ko.mapping.fromJS(options.data, self.mappingOptions, this);
})());
}
},
'EmployeesWorkedWith': {
create: function (options) {
// return new instance.EmployeesWorkedWithModel(options);
return (new(function(){
ko.mapping.fromJS(options.data, {}, this);
this.nameUpper = ko.computed(function () {
return this.EmployeeName().toUpperCase();
}, this);
})());
}
}
};
Notice I have used "self" as your local reference to 'this' instead of 'instance', just to make the code easier to read (as you used 'instance' in the main viewmodel).
I have also made the mappingOptions object part of the FeedbackViewModel, as we need to pass this into the mapping.fromJS call so when it sees the 'EmployeesWorkedWith' level in the data it will have the mappingOptions for it.
From:
ko.mapping.fromJS(options.data, {}, this);
To:
ko.mapping.fromJS(options.data, self.mappingOptions, this);
You can then move your creation code for 'EmployeesWorkedWith' level into the create (you could call a function, but I've kept it together in the mappingOptions as shown above, like the way you were creating the 'EmployeeFeedbackRequestSubmissions' level.
You can then get rid of the instance.EmployeesWorkedWithModel function altogether.
A working fiddle can be found here:
http://jsfiddle.net/jiggle/na93A/
Alternatively, you could create separate mappingOptions object when you are in the create for 'EmployeeFeedbackRequestSubmissions' and not have the mappings for all levels in one object, which can be seen in this fiddle http://jsfiddle.net/jiggle/Avam7/
Depends on your coding style which way you prefer, and would be important to separate them out if you had different mapping needs for different levels and they had the same collection name.
eg.
Employees
Employee
Employees (you might need different computeds, etc. at this level)
If so, you would use the second option (separate the mappingOptions and pass to the level that will use it)
I've added some console.log statements to the fiddles so you can see values as the code runs in the console, which will help to understand how it's working.
Hope it helps.
Nice thing with ko.mapping is how automated the process can be.
Check out the results in http://jsfiddle.net/9ejJq/26/
You'll note how we only use one declared mapping to kick things off.
feedbackMappingOptions = {
create: function (options) {
return new FeedbackViewModel(options.data);
}
};
From there on, each view model triggers a mapping for their child objects. You could go as far as creating a mapping option for each or, as you see for the final ProjectsWorked object under the EmployeesWorkedWith, we just throw the data right at a mapping and ko.mapping does the rest. Hope this helped.