I am trying to implement my first PWA service worker and I have referred only google documentation. For now my manifest.json is complete and the service worker is a simple code as below.
// sw.js
var CACHE_NAME = "MyFirstPWA";
var filesToCache = [
// some css and js files to cache
];
self.addEventListener('install', function (e) {
e.waitUntil(caches.open(CACHE_NAME).then(function (cache) {
return cache.addAll(filesToCache);;
}).then(function (e) {
return self.skipWaiting();
}));
});
self.addEventListener('activate', function (event) {
event.waitUntil(caches.keys().then(function (cacheNames) {
return Promise.all(cacheNames.map(function (cacheName) {
return caches.delete(cacheName);
}));
}));
});
self.addEventListener('fetch', function (event) {
event.respondWith(caches.match(event.request).then(function (response) {
return response || fetch(event.request);
}).catch(function (e) {
console.log(e);
}));
});
// Manifest.json
{
"name": "MyFirstPWA",
"short_name": "MyFirstPWA",
"icons": [
{
"src": "/images/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "/images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "/images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "/images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/images/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/?utm_source=pwa&utm_medium=pwa",
"orientation": "portrait",
"display": "standalone",
"theme_color": "#0054a6",
"background_color": "#ffffff",
"scope": "/",
"splash_pages": null
}
The working status of google's mini-info bar feature as below.
I want to know if I am missing something or have implemented wrongly?
Please suggest.
Related
Good morning!
These days i've been working on a pokemon-based project.
My issue to solve right now is to solve the function located at service which gets the pokemons array of a trainer (function below):
getPokemonsOfATrainer(nombreEntrenador: string){
return this.http.get<Trainer>(`${this.apiUrl1}?fullName=${nombreEntrenador}`).pipe(
map( (entrenador: Trainer) => {
return entrenador.pokemons;
})
);
}
My mocked JSON (example of 1 trainer), it's in the following format:
{
"entrenadores": [
{
"fullName": "Alecs",
"pokemons" : [
{
"name":"Venusaur",
"nature": "Calm",
"attacks": [
{
"name":"Leech Seed",
"type":"Grass",
"style":"Attack"
},
{
"name":"Sleep Powder",
"type":"Grass",
"style":"Support"
},
{
"name":"Grass Knot",
"type":"Grass",
"style":"Attack"
},
{
"name":"Sludge Bomb",
"type":"Poison",
"style":"Attack"
}
]
},
{
"name": "Skarmory",
"nature": "Impish",
"attacks": [
{
"name": "Slash",
"type": "Normal",
"style": "Attack"
},
{
"name": "Spikes",
"type": "Bug",
"style": "Support"
},
{
"name": "Brave Bird",
"type": "Flying",
"style": "Attack"
},
{
"name": "Rock Slide",
"type": "Rock",
"style": "Attack"
}
]
},
{
"name": "Registeel",
"nature": "Careful",
"attacks": [
{
"name": "Focus Blast",
"type": "Fighting",
"style": "Attack"
},
{
"name": "Hyper Beam",
"type": "Normal",
"style": "Attack"
},
{
"name": "Shadow Claw",
"type": "Dark",
"style": "Attack"
},
{
"name": "Rock Smash",
"type": "Rock",
"style": "Attack"
}
]
},
{
"name": "Uxie",
"nature": "Impish",
"attacks": [
{
"name": "Future Sight",
"type": "Psychic",
"style": "Support"
},
{
"name": "Memento",
"type": "Normal",
"style": "Support"
},
{
"name": "Dazzling Gleam",
"type": "Psychic",
"style": "Support"
},
{
"name": "Drain Punch",
"type": "Fighting",
"style": "Attack"
}
]
},
{
"name": "Gallade",
"nature": "Adamant",
"attacks": [
{
"name": "Hypnosis",
"type": "Psychic",
"style": "Support"
},
{
"name": "Night Slash",
"type": "Ghost",
"style": "Attack"
},
{
"name": "Brick Break",
"type": "Fighting",
"style": "Attack"
},
{
"name": "Close Combat",
"type": "fighting",
"style": "Support"
}
]
}
]
}
]
}
Would exist a proper way to get the pokemons of a trainer?
Thanks in advance!
You should use HttpClientTestingModule and follow the standard way how to stub the response of http requests. For example, this one: https://ng-mocks.sudo.eu/guides/http-request
Your test can look like:
describe('suite', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [HttpClientTestingModule], // <- add
providers: [PokemonService],
}).compileComponents());
it('test', () => {
// getting the service and httpMock
const service = TestBed.inject(PokemonService);
const httpMock = TestBed.inject(HttpTestingController);
// subscribing to the result of the http request
let actual: any;
service.getPokemonsOfATrainer('trainer')
.subscribe(value => actual = value);
// stubbing the http request
const req = httpMock.expectOne('<PUT_HERE_API_URL>?fullName=Alecs');
expect(req.request.method).toEqual('GET');
req.flush(mockedJson.entrenadores);
httpMock.verify();
// asserting that we got what expected
expect(actual).toEqual(mockedJson.entrenadores.pokemons);
});
});
I have an app.json file in my Expo project. In this file I have two API keys (labeled API_KEY below) that I'd like to hide via environment variables.
How can I go about using environment variables instead of hard coding the API keys?
app.json
{
"expo": {
"name": "Closeout",
"slug": "Closeout",
"version": "1.0.0",
"orientation": "portrait",
"privacy": "hidden",
"notification": {
"icon": "./assets/images/notification-icon.png",
"color": "#000000",
"iosDisplayInForeground": true
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"icon": "./assets/images/icon.png",
"buildNumber": "2",
"config": {
"googleMapsApiKey": "API_KEY"
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/icon.png",
"backgroundColor": "#000"
},
"versionCode": 5,
"useNextNotificationsApi": true,
"config": {
"googleMaps": {
"apiKey": "API_KEY"
}
},
"googleServicesFile": "./google-services.json"
}
}
}
I'm guessing you may have figured out a solution or tried something else by now. However, here is a solution to this issue, I hope it helps anyone facing the same challenge. This is from a typescript environment I'm implementing.
Create an app.config.ts file that overrides the content of the app.json file
import { ExpoConfig, ConfigContext } from '#expo/config';
import * as dotenv from 'dotenv';
// initialize dotenv
dotenv.config();
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
slug: 'my-app',
name: 'My App',
ios: {
supportsTablet: true,
bundleIdentifier: 'com.croon',
config: {
googleMapsApiKey: process.env.GOOGLE_CLOUD_API_KEY,
},
},
android: {
adaptiveIcon: {
foregroundImage: './assets/adaptive-icon.png',
backgroundColor: '#FFFFFF',
},
package: 'com.croon',
config: {
googleMaps: {
apiKey: process.env.GOOGLE_CLOUD_API_KEY,
},
},
},
});
Then you could leave the API entry blank on the app.json file.
{
"expo": {
"name": "Closeout",
"slug": "Closeout",
"version": "1.0.0",
"orientation": "portrait",
"privacy": "hidden",
"notification": {
"icon": "./assets/images/notification-icon.png",
"color": "#000000",
"iosDisplayInForeground": true
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"icon": "./assets/images/icon.png",
"buildNumber": "2",
"config": {
"googleMapsApiKey": ""
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/icon.png",
"backgroundColor": "#000"
},
"versionCode": 5,
"useNextNotificationsApi": true,
"config": {
"googleMaps": {
"apiKey": ""
}
},
"googleServicesFile": "./google-services.json"
}
}
}
Remember to install the required dependencies
Cheers!
Inside the body tag of this html file, I have a button that clicking it should result in getting contents of colors.json into console.
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<script type="primary" src="colors.json"></script>
<script type="text/javascript">
function load() {
var someData_notJSON = JSON.parse(data);
console.log(someData_notJSON[0].red);
}
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'colors.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
callback(xobj.responseText);
}
};
xobj.send(null); //line 24
}
function init() {
loadJSON(function(response) {
var actual_JSON = JSON.parse(response);
console.log(actual_JSON);
});
}
</script>
<title></title>
</head>
<body>
<button type="button" name="button" onclick=" init()">Click me</button>
</body>
</html>
And here is the colors.json file:
{
"colors": [
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
},
]
}
On page load I get this error: Uncaught SyntaxError: Unexpected token :
Do you know what causes this issue?
It could be that you have an unnecessary comma at the end of your array:
{
"colors": [
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
}
]
}
{
"colors": [
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
}
]
}
Can you remove the last comma and try it out.
I'm having a problem with a PWA I'm developing using Angular. After adding the app to the homescreen in a mobile device, I tried to open it from the home screen but instead of showing the menu, just after the splash screen it shows me my manifest.json file.
{
"name": "Bitpoint",
"short_name": "Bitpoint",
"theme_color": "#03A9F4",
"background_color": "#03A9F4",
"display": "standalone",
"Scope": "/",
"orientation": "portrait",
"start_url": "#/app/recibirpago",
"icons": [
{
"src": "assets/images/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "assets/images/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "assets/images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "assets/images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "assets/images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "assets/images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/images/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "assets/images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
You can check this error by yourself going to my app and adding the app to your homescreen.
In start_url to need to set a path to the index.html file, for example:
"start_url": "index.html/#/app/recibirpago", or
"start_url": "./#/app/recibirpago",
I added / for starturl
start_url:"/"
I am trying to create a file explorer kind of project. I am using angularjs for this. The thing is I am having trouble to get the data from the json file which I created manually.
My json data
[
{
"id": 0,
"name": "Nature",
"images": [
{
"id": 0,
"src": "images/nature/01.jpg",
"thumb": "images/nature/01-thumb.jpg",
"name": "Nature View"
},
{
"id": 1,
"src": "images/nature/02.jpg",
"thumb": "images/nature/02-thumb.jpg",
"name": "Nature View"
},
{
"id": 2,
"src": "images/nature/03.jpg",
"thumb": "images/nature/03-thumb.jpg",
"name": "Nature View"
},
{
"id": 3,
"src": "images/nature/04.jpg",
"thumb": "images/nature/04-thumb.jpg",
"name": "Nature View"
}
]
},
{
"id": 1,
"name": "Lanscape",
"images": [
{
"id": 0,
"src": "images/landscape/01.jpg",
"thumb": "images/landscape/01-thumb.jpg",
"name": "Landscape View"
},
{
"id": 1,
"src": "images/landscape/02.jpg",
"thumb": "images/landscape/02-thumb.jpg",
"name": "Landscape View"
},
{
"id": 2,
"src": "images/landscape/03.jpg",
"thumb": "images/landscape/03-thumb.jpg",
"name": "Landscape View"
},
{
"id": 3,
"src": "images/landscape/04.jpg",
"thumb": "images/landscape/04-thumb.jpg",
"name": "Landscape View"
}
]
},
{
"id": 2,
"name": "Movies",
"images": [
{
"id": 0,
"src": "images/movies/01.jpg",
"thumb": "images/movies/01-thumb.jpg",
"name": "Ipsum View"
},
{
"id": 1,
"src": "images/movies/02.jpg",
"thumb": "images/movies/02-thumb.jpg",
"name": "Ipsum View"
},
{
"id": 2,
"src": "images/movies/03.jpg",
"thumb": "images/movies/03-thumb.jpg",
"name": "Ipsum View"
},
{
"id": 3,
"src": "images/movies/04.jpg",
"thumb": "images/movies/04-thumb.jpg",
"name": "Ipsum View"
}
]
}
]
It is a file explorer so thought it should have category name and it will have images in it. That's the reason this structure.
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular-route.min.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
app.js
var app = angular.module('myApp', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'home.html',
controller: 'mainCtrl'
}).
when('/:id', {
templateUrl: 'detail.html',
controller: 'detailCtrl'
}).
otherwise({
redirectTo: '/'
});
});
app.controller('mainCtrl', function($http, $scope) {
$http.get('data.json').success(function (data) {
$scope.mainData = data;
});
});
app.controller('detailCtrl', function($http, $scope, $routeParams) {
$scope.id = $routeParams.id;
$http.get('data.json').success(function (data) {
angular.forEach(data, function (temp) {
$scope.mainData = temp.images;
});
});
});
home.html
<ul ng-repeat="data in mainData">
<li>{{data.name}}</li>
</ul>
detail.html
<div ng-repeat="data in mainData">
<h1>{{data.name}}</h1>
<img src="{{data.thumb}}" />
</div>
When I loop into images the data is displayed same for every id. What I am trying is when I click on nature I want the nature images and it's data to be displayed. I have created a plunkr http://plnkr.co/edit/aR7PM2KQw7XsCtGTYvtI?p=preview
Please help me with this as I'm having trouble understanding this one.
The problem is the detailCtrl you are allways setting mainData to last element. Quick Fix:
app.controller('detailCtrl', function($http, $scope, $routeParams) {
$scope.id = $routeParams.id;
$http.get('data.json').success(function (data) {
$scope.mainData = data[$scope.id].images;
});
});
Plunker Edited: http://plnkr.co/edit/3G2TFGvgfW4EihhS4oo4?p=preview
Extended Edit:
This works but is not the way to work in angular, you should wrap your data access into a factory, and then resolve the data model in the router before loading the view. Right now you are fetching the data each time, when you should only do this one time.