How do I cache dynamic (JSON) content in Angular on app load? - json

I am trying to build a demo app with dynamic JSON content that needs to be cached on app load so the urls (router ui) can be accessed immediately.
The "View info for Jack Burton" link at the top only shows his info only after it's been previously loaded (even then, it's screwy):
Example plunker: http://plnkr.co/edit/xIzq8cy4ZsZC9Dz5Cbpv?p=preview
I need to access content about a "person" from other links throughout the app, I'm guessing through in-app urls, not sure what the best practice is for this.
Thanks!
HTML
index.html
<div class="row">
<div class="col-sm-12">
<a ng-href="#/" class="btn-link">Home</a> |
<a ng-href="#/jack-burton">View Info for Jack Burton (Only works after it's cached)</a>
<div class="well" ui-view></div>
</div>
</div>
home.html
<h1>People</h1>
<ul class="list-unstyled">
<li ng-repeat="person in people">
<a ng-href="#/{{ person.url }}" ng-click="setPeopleContent(person)">
{{person.name}}
</a>
</li>
</ul>
person.html
<h1>{{peopleContent.name}}</h1>
<section id="contact" ng-if="peopleContent.hasContact">
<h4>Contact Info</h4>
<p ng-repeat="item in peopleContent.contact" ng-if="contentExists(item.address)">
Address: {{item.address}}
</p>
<p ng-repeat="item in peopleContent.contact" ng-if="contentExists(item.phone)">
Phone: {{item.phone}}
</p>
<p ng-repeat="item in peopleContent.contact" ng-if="contentExists(item.email)">
Email: {{item.email}}
</p>
</section>
<section id="pastJobs" ng-if="peopleContent.hasPastJobs">
<h4>Past Jobs</h4>
<p ng-repeat="item in peopleContent.pastJobs" ng-if="contentExists(item.job)">
Job: {{item.job}}
</p>
<p ng-repeat="item in peopleContent.pastJobs" ng-if="contentExists(item.jobTitle)">
Title: {{item.jobTitle}}
</p>
</section>
<section id="goals" ng-if="peopleContent.hasGoals">
<h4>Goals</h4>
<ul class="list-unstyled">
<li ng-repeat="item in peopleContent.goals" ng-if="contentExists(item.goal)">
{{item.goal}}
</li>
</ul>
</section>
JSON
{
"people": [
{
"name": "Alexander Supertramp",
"url": "alexander-supertramp",
"contact": [
{
"address": "Alaska"
}
],
"goals": [
{
"goal": "Climb Mt Everest"
},
{
"goal": "Travel in space"
},
{
"goal": "Become a rocket scientist"
}
]
},
{
"name": "Gordon Bombay",
"url": "gordon-bombay",
"pastJobs": [
{
"job": "Hockey Coach",
"jobTitle": "Coach"
},
{
"job": "Hockey Player",
"jobTitle": "Goalie"
}
],
"goals": [
{
"goal": "Win the stanley cup"
},
{
"goal": "Be a cool guy"
}
]
},
{
"name": "Jack Burton",
"url": "jack-burton",
"contact": [
{
"address": "China Town",
"phone": "555-555-getMyTruckBack",
"email": "porkchopexpress#gmail.com"
}
],
"pastJobs": [
{
"job": "Porkchop Express Driver",
"jobTitle": "Truck Driver"
}
],
"goals": [
{
"goal": "Get his truck back"
},
{
"goal": "Stay alive"
},
{
"goal": "Get with Kim Cattrall"
}
]
},
{
"name": "Eric Roberts",
"url": "eric-roberts",
"contact": [
{
"address": "New York City",
"email": "ambulance911#gmail.com"
}
],
"goals": [
{
"goal": "Become a comicbook artist"
},
{
"goal": "Find that woman from the street"
},
{
"goal": "Stay alive"
},
{
"goal": "Don't get run over by an evil ambulance"
}
]
}
]
}
JS
var myapp = angular.module('demoApp', ["ui.router"])
myapp.config(function($stateProvider, $urlRouterProvider){
$stateProvider
.state('home', {
url: "/",
templateUrl: "home.html"
})
.state('person', {
url: "/:person",
templateUrl: "person.html"
})
$urlRouterProvider.otherwise("/")
});
function MainController($scope, $http, $stateParams) {
$http.get('demo-data.json', { cache: true}).success(function(data){
$scope.people = data.people;
});
$scope.person = $stateParams.person;
$scope.setPeopleContent = function(person) {
$scope.peopleContent = person;
$scope.peopleContent.hasContact = ($scope.peopleContent.contact instanceof Array);
$scope.peopleContent.hasPastJobs = ($scope.peopleContent.pastJobs instanceof Array);
$scope.peopleContent.hasGoals = ($scope.peopleContent.goals instanceof Array);
};
// Checks if contentValue is undefined / exists
$scope.contentExists = function(contentValue) {
if(contentValue != undefined) {
return true;
}
};
};

You should use either localStorage or sessionStorage here is more info: link
Here is one example of how I use it with angular:
Note I'm storing date to when was last time I've saved data to storage (and if data is too old I get data again from server and save it to storage)
var retreivedStorageData = JSON.parse(window.sessionStorage.getItem("basicUserInfo"));
if (retreivedStorageData) {
var differenceInMs = Math.abs(new Date() - new Date(retreivedStorageData.date));
// check how old is data
if (differenceInMs <= 60 * 1000) {
$scope.ImageUrl = retreivedStorageData.item.ImageUrlSmall;
$scope.UserName = retreivedStorageData.item.Name;
} else {
//if it's too old get it from server
getDataFromServer();
}
} else {
getDataFromServer();
}
function getDataFromServer() {
$http.get("/Profile/GetUserBasicInfo/")
.success(function(result) {
/*More code here*/
if (typeof (window.Storage) != "undefined") {
var storageData = JSON.stringify({ item: result, date: new Date() });
window.sessionStorage.setItem("basicUserInfo", storageData);
}
});
}

Related

Vue.js Filtered list Method

I am still learning Vue.js. At the moment I am trying to make a simple filtered list method that pulls the data from a json file in Vue. I think that I am having trouble figuring out the correct syntax.
I just cant seem to get it right. Any help is more than welcome :)
This is Vue file:
<template>
<section>
<ul>
<li v-for="product in rings" :key="product">
{{product.title}}
</li>
</ul>
</section>
</template>
<script>
import data from '#/assets/data.json';
export default {
data() {
return {
products: []
}
},
methods: {
computed: {
rings(){
return this.products.filter(product => product.type == 'Ring')
}
}
}
}
</script>
And this is the Json file:
{ "products": [
{
"title": "Ring 1",
"description": "something",
"type": "Ring",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
},
{
"title": "Halskæde 1",
"description": "something",
"type": "Halskæde",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
},
{
"title": "Armbånd 1",
"description": "something",
"type": "Armbånd",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
},
{
"title": "Ørering 1",
"description": "something",
"type": "Ørering",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
}
]
}
You imported the data but never used anywhere inside the component:
import data from '#/assets/data.json';
// notice the data here is just a variable and it has nothing to do with the
// component's data property
export default {
data () {
return {
products: data.products // init products with imported data
}
},
Or with the destructuring syntax:
import { products } from '#/assets/data.json';
export default {
data () {
return {
products // init products with imported data
}
},

Set next step for the waterfall dialogue in Microsoft BotBuilder NodeJS SDK

I am using Microsoft Bot Framework for my facebook messenger bot. I want to load the dialog data from json files instead of hard coding in the js file. I would like to configure the next step in the dialog, based on result from the "current" step, which is part of the json file configuration, something like this.
{
"name": "welcome",
"type": "waterfall",
"steps": [
{
"id": 0,
"data": [
{
"type": "text",
"value": "Hey, It's nice to meet you."
},
{
"type": "quickReplies",
"value": "What do you want to do next?",
"options": [
{
"text": "some option 1",
"value": "option1"
},
{
"text": "some option 2",
"value": "option2"
}
]
}
],
"next": [
{
"result": "option1",
"action": "goto step 2"
},
{
"result": "option2",
"action": "goto step 5"
}
]
}
]
}
I would like to process all the incoming messages and respond with correct dialog or correct step in the dialog for the user.
I am trying something like this;
handleMessage = function (session) {
var step = session.dialogData["BotBuilder.Data.WaterfallStep"] || 0;
// check response data from previou step and identify the next step.
// set the waterfall step id
session.dialogData["BotBuilder.Data.WaterfallStep"] = 2;
session.send("Hello");
}
var bot = new builder.UniversalBot(connector, function (session) {
handleMessage(session);
})
.set('storage',tableStorage);
With this code, I am always getting step as zero for session.dialogData["BotBuilder.Data.WaterfallStep"] even after setting this to a different number.
Also, as soon as I set the waterfall step number, all other state data that is stored in my table storage for this conversation is gone.
Storage data before setting waterfall step:
{
"BotBuilder.Data.SessionState": {
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 0
}
},
{
"id": "*:welcome",
"state": {
"BotBuilder.Data.WaterfallStep": 1
}
},
{
"id": "BotBuilder:prompt-text",
"state": {
"options": {
"prompt": {
"type": "message",
"agent": "botbuilder",
"source": "facebook",
"address": {
"id": "mid.$cAAAlr-0LRH9niO21L1hV6hs83GuJ",
"channelId": "facebook",
"user": {
"id": "XXXX",
"name": "XXXX"
},
"conversation": {
"isGroup": false,
"id": "XX"
},
"bot": {
"id": "XXX",
"name": "XXX"
},
"serviceUrl": "https://facebook.botframework.com"
},
"text": "what do you want to next"
//ignored for simplicity
},
"promptAfterAction": true,
"libraryNamespace": "*"
},
"turns": 0,
"lastTurn": 1517594116372,
"isReprompt": false
}
}
],
"lastAccess": 1517594112740,
"version": 0
}
}
After I set the waterfall step:
{
"BotBuilder.Data.SessionState": {
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 2
}
}
],
"lastAccess": 1517602122416,
"version": 0
}
}
Interestingly the step number is saved to the database (but in session state) but my "session" variable do not have this value anywhere. Also, even after configuring custom state service, the serviceUrl is still https://facebook.botframework.com which I thought is the default state service used if there is no state service set for the bot.
Per your code, as your bot actually contains only one waterfall step: handleMessage(session);, which raised your issue. You can consider to create multiple dialogs from json configration instead of complex waterfall steps.
Here is my quick test, for your information:
const json = `
[{
"name": "welcome",
"type": "waterfall",
"steps": [
{
"id": 0,
"data": [
{
"type": "text",
"value": "Hey, It's nice to meet you."
},
{
"type": "quickReplies",
"value": "What do you want to do next?",
"options": [
{
"text": "some option 1",
"value": "option1"
},
{
"text": "some option 2",
"value": "option2"
}
]
}
],
"next": [
{
"result": "option1",
"action": "dialog2"
},
{
"result": "option2",
"action": "dialog3"
}
]
}
]
},{
"name":"dialog2",
"type": "waterfall",
"steps": [
{
"data": [
{
"type": "text",
"value": "Hey, this is dialig2."
}]
}
]
},{
"name":"dialog3",
"type": "waterfall",
"steps": [
{
"data": [
{
"type": "text",
"value": "Hey, this is dialig3."
}]
}
]
}]
`;
const generateSignleStep = (step) => {
return (session, args, next) => {
step.forEach(sentence => {
switch (sentence.type) {
case 'quickReplies':
let choices = sentence.options.map(item => {
return item.value
});
let card = new builder.ThumbnailCard(session)
.text(sentence.value)
.buttons(sentence.options.map(choice => new builder.CardAction.imBack(session, choice.value, choice.text)))
let message = new builder.Message(session).addAttachment(card);
builder.Prompts.choice(session, message, choices);
break;
case 'text':
default:
session.send(sentence.value)
break;
}
})
}
}
const generatenextAction = (actions) => {
return (session, args, next) => {
const response = args.response;
actions.map(action => {
if (action.result == response.entity) {
session.beginDialog(action.action);
}
})
}
}
const generateWaterfallSteps = (steps) => {
let waterfall = [];
steps.forEach(step => {
waterfall.push(generateSignleStep(step.data));
if (step.next) {
waterfall.push(generatenextAction(step.next));
}
});
return waterfall;
}
var bot = new builder.UniversalBot(connector);
const jsonobj = JSON.parse(json);
jsonobj.forEach(dialog => {
bot.dialog(dialog.name, generateWaterfallSteps(dialog.steps))
.triggerAction({
matches: new RegExp(dialog.name, "g")
})
});
The result is:

How to get response (array of json) and put it in my html component in Angular 4

I am trying to get the array data in a JSON response. The following is my JSON response and I need to get all data to my html tags in component.
{
data : {
"topLikedMedia" : [
{
"id": "1546567845943506613_3718981156",
"type": "image",
"user": {
"id": "3718981156",
"username": "agoramonitor",
"full_name": "AgoraMonitor",
"profile_picture": "https://scontent.cdninstagram.com/t51.2885-19/s150x150/18809269_476795959342067_7353566623065702400_n.jpg"
},
"tags": [
"instagramers",
"content",
"socialmedia",
"marketing",
"branding",
"instagram"
],
"location": null,
"comments": {
"count": 2
},
"formatted_comments_count": "2",
"created_time": "1498585275",
"formatted_time": "Tue, Jun 27, 2017 7:41 PM",
"diff_humans_time": "4 months ago",
"link": "https://www.instagram.com/p/BV2g0MGgPa1/",
"likes": {
"count": 154
},
"formatted_likes_count": "154",
"images": {
"thumbnail": {
"width": 150,
"height": 150,
"url": "https://scontent.cdninstagram.com/t51.2885-15/s150x150/e35/c244.0.591.591/19533988_862713503881059_8677706625265434624_n.jpg"
},
"low_resolution": {
"width": 320,
"height": 175,
"url": "https://scontent.cdninstagram.com/t51.2885-15/s320x320/e35/19533988_862713503881059_8677706625265434624_n.jpg"
},
"standard_resolution": {
"width": 640,
"height": 350,
"url": "https://scontent.cdninstagram.com/t51.2885-15/s640x640/sh0.08/e35/19533988_862713503881059_8677706625265434624_n.jpg"
}
},
"caption": "Whether you want to drive leads to your homepage or encourage customer engagement ",
"userHasLiked": false,
"filter": "Normal"
}
],
}
I have the temp of this output and I need to receive this response and distribute it on its own tags and i dont know how
First solution, the Angular way :
getTopLiked() {
this._dashboardService.getTopPosts()
.subscribe(res => {
// Get your data in your component's variable
this.data = res.json();
});
}
In your HTML
<div *ngIf="data">
<div *ngFor="let liked of data.topLikedMedia">
<p>ID : {{liked.id}}</p>
<!-- And you do every other field like that -->
</div>
</div>
Second solution, the old Javascript way
getTopLiked() {
this._dashboardService.getTopPosts()
.subscribe(res => {
this.createMarkup(res.json());
});
}
createMarkup(data: Object) {
this.markup = '';
for (let liked of data.topLikedMedia) {
this.markup += `<p>ID : ${liked.id}</p>`;
// add the other fields like that
}
}
In your HTML
<div *ngIf="markup">
<div [innerHTML]="markup"></div>
</div>

How to display data from a json file in angularjs?

I have a json something like this
{
"count": 67,
"0": {
"id": "2443",
"name": "Art Gallery",
"category": {
"id": "2246",
"name": "Gifts & Memories"
},
"deckLocation": [
{
"id": "2443",
"deck": {
"deckNo": "7",
"deckName": "Promenade "
},
}
]
},
"1": {
"id": "7198",
"name": "Captain's Circle Desk",
"category": {
"id": "352",
"name": "Other Services"
},
"deckLocation": [
{
"id": "7198",
"deck": {
"deckNo": "7",
"deckName": "Promenade "
},
},
{
"id": "7198",
"deck": {
"deckNo": "7",
"deckName": "Promenade "
},
}
]
}
}
I want to display all names which is inside the "0", "1" array. I can able to list a specific name but not all. The fist name will display which I written in the following code. But I need to display all 0, 1, 2, 3 etc names dynamically.
data[0].name
Please help me.
Thank you.
use ng-repeat function to do so.
<div ng-repeat = "names in data">
<P>{{names.name}}</P>
</div>
Let us say you have a service like this:-
var todoApp = angular.module("todoApp",[]);
todoApp.factory('dbService', ['$q','$http',function ($q , $http) {
var service ={};
service.getUrl = function (urlToGet) {
var svc=this;
var deferred = $q.defer();
var responsePromise = $http.get(urlToGet);
responsePromise.success(function (data, status, headers, config) {
deferred.resolve(data); });
responsePromise.error(function (data, status, headers, config) {
deferred.reject({ error: "Ajax Failed", errorInfo: data });});
return (deferred.promise);
}
return service;
}]);
And you want to load a file named '/js/udata.json'. Here is how in you controller you can load this file:-
todoApp.controller("ToDoCtrl", ['$scope','$timeout','dbService',function($scope, $timeout, dbService)
{
$scope.todo={};
$timeout(function(){
dbService.getUrl('/js/udata.json').then(function(resp){
$scope.todo=resp;
});},1);
};
Hope this helps!
You have data[0].name right?
then why don't you loop through that to get all the name elements in those arrays.
like...
for(i=1;i<data.length;i++)
{
console.log(data[i].name);
}

How do I use knockout to bind nested foreach loops on dynamically added properties?

I have a collection of items. The items are broken down into "types" and then further divided within the type into "categories". I do not know the names of the "types" or the "categories" before hand.
I would like to do some nested foreach binding to represent the data hierarchically. Something like this:
<ul data-bind="foreach: OrderItems.Types">
<li>
ItemType: <span data-bind='text: $data'></span>
<ul data-bind="foreach: Categories">
<li>
Category: <span data-bind='text: $data'></span>
<ul data-bind="foreach: OrderItems">
<li>
Item: <span data-bind="text: Name"> </span>
</li>
</ul>
</li>
</ul>
</li>
var order = {
"OrderNumber": "394857",
"OrderItems": {
"Types": {
"Services": {
"Categories": {
"carpet cleaning": {
"OrderItems": [
{
"OrderItemID": "9d398f88-892c-11e3-8f31-18037335d26a",
"Name": "ARug-Oriental Rugs (estimate on site)"
},
{
"OrderItemID": "9d398f53-892c-11e3-8f31-18037335d26a",
"Name": "C1-Basic Cleaning (per room)"
},
{
"OrderItemID": "9d398f54-892c-11e3-8f31-18037335d26a",
"Name": "C2-Clean & Protect (per room)"
},
{
"OrderItemID": "9d398f55-892c-11e3-8f31-18037335d26a",
"Name": "C3-Healthy Home Package (per room)"
}
]
},
"specialty": {
"OrderItems": [
{
"OrderItemID": "9d398f8f-892c-11e3-8f31-18037335d26a",
"Name": "SOTHR-Other"
}
]
},
"tile & stone": {
"OrderItems": [
{
"OrderItemID": "9d398f8e-892c-11e3-8f31-18037335d26a",
"Name": "TILE-Tile & Stone Care"
}
]
},
"upholstery": {
"OrderItems": [
{
"OrderItemID": "9d398f7b-892c-11e3-8f31-18037335d26a",
"Name": "U3S1-Upholstery - Sofa (Seats 3: 7 linear feet)"
},
{
"OrderItemID": "9d398f7c-892c-11e3-8f31-18037335d26a",
"Name": "U3S2-Upholstery - Sofa - Clean & Protect (Seats 3: 7 linear feet"
}
]
}
}
},
"Products": {
"Categories": {
"carpet cleaning": {
"OrderItems": [
{
"OrderItemID": "9d398f84-892c-11e3-8f31-18037335d26a",
"Name": "PLB-Leave Behind Item"
}
]
}
}
}
}
}
};
var viewModel = ko.mapping.fromJS(order);
ko.applyBindings(viewModel);
here's a fiddle with the above code: http://jsfiddle.net/mattlokk/6Q5f7/5/
To bind against your structure, you would need to turn the objects into arrays. Given that you are using the mapping plugin, the easiest way would likely be to use a binding that translates an object with properties to an array of key/values.
Here is a sample binding:
ko.bindingHandlers.objectForEach = {
init: function(element, valueAccessor, allBindings, data, context) {
var mapped = ko.computed({
read: function() {
var object = ko.unwrap(valueAccessor()),
result = [];
ko.utils.objectForEach(object, function(key, value) {
var item = {
key: key,
value: value
};
result.push(item);
});
return result;
},
disposeWhenNodeIsRemoved: element
});
//apply the foreach bindings with the mapped values
ko.applyBindingsToNode(element, { foreach: mapped }, context);
return { controlsDescendantBindings: true };
}
};
This will create a computed on-the-fly that maps the object to an array of key/values. Now you can use objectForEach instead of foreach against your objects.
Here is a basic sample: http://jsfiddle.net/rniemeyer/nn3jg/ and here is an example with your fiddle: http://jsfiddle.net/rniemeyer/47Wbe/