Angular Routing - Direct path access not working from URL - angular-routing

I created and host www.xinthose.com. This is the source code for the website. When you navigate to the website, it will take you to the path /home, but when you try to duplicate that tab or go directly to www.xinthose.com/home, I get a 404 error from HostGater (my website host). This is the contents of app-routing.module.ts:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { HomeComponent } from './home/home.component';
import { BibleComponent } from './bible/bible.component';
import { AboutComponent } from './about/about.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'bible', component: BibleComponent },
{ path: 'about', component: AboutComponent },
{ path: '**', component: PageNotFoundComponent },
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Why is this happening and how do I fix it? Is it related to pathMatch at all? Am I missing some Route property?

Alternative solution, May 2022:
This is probably a very late answer and I see that you have already solved your question. However, here is an alternative (free hosting but depending on the services you use it can be paid):
You can use Firebase Hosting to host your angular application for free. There is the possibility to also use your own domain if you don't want to use the default urls generated from Firebase. I had initially hosted my application elsewhere, which resulted in the same problem that you described above, however hosting the application using Firebase solved this issue for me.
You can implement firebase in your application simply from the Firebase documentation (link above) or a simpler solution is to implement it using angular/angularfire which is the official implementation of Firebase for Angular. Please install the library with ng add #angular/fire and follow the instructions given in the terminal.

This is not because of the web app route roles.
Angular applications have to become installed , and available so , angular router can be usable , so , when ever you try to access route like this 'domain/home' , you will get 404 error.
There is three solution that i know right now
1st 'best'
Angular universal
2nd
If your host is something like apache , that use php files, try to rewrite routes like this
search for rewrite urls for any other kind of host servers
.htaccess
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www.domain.com$ [NC]
RewriteRule ^(.*)$ https://app.domain.com/$1 [L,R=301]
3rd
Use PWA
this one is awesome, but still , application have to be installed on user device , but after first launch , direct routes will work

It took me almost a year, but I figured out that you have to pay for node.js hosting, AWS elastic beanstalk is a good candidate for this. Then you have to serve your static compiled website using something like express.js. This is my working example server.js:
"use strict";
const express = require("express");
const compression = require('compression');
// config
const port = process.env.PORT || 3000;
const app_folder = "./";
const options = {
dotfiles: 'ignore',
etag: false,
extensions: ['html', 'js', 'scss', 'css'],
index: false,
maxAge: '1y',
redirect: true,
}
// create app
const app = express();
app.use(compression());
app.use(express.static(app_folder, options));
// serve angular paths
app.all('*', function (req, res) {
res.status(200).sendFile(`/`, {root: app_folder});
});
// start listening
app.listen(port, function () {
console.log("Node Express server for " + app.name + " listening on http://localhost:" + port);
});
Then in package.json you have a start command the website host will run:
{
"name": "xinthose.com",
"scripts": {
"ng": "ng",
"start": "node server.js",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"dependencies": {...},
"devDependencies": {...}
}
This is the only way to serve pages dynamically on a static single page application.

Related

How to deploy an generate a static site on Nuxt 3

Hello I'm creating website on Nuxt and i have created a new app on Nuxt 3. But I have an probleme for the deployement, there is no 'normal' build for 'normal server' as Nuxt 2.x.
I'm using 'Lamdba' preset.
https://v3.nuxtjs.org/docs/deployment/presets/lambda
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt3'
// https://v3.nuxtjs.org/docs/directory-structure/nuxt.config
export default defineNuxtConfig({
// Global page headers: https://go.nuxtjs.dev/config-head
nitro: {
preset: 'lambda'
},
head: {
title: 'Title',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
],
link: [
{ rel: 'icon', type: 'image/png', href: '/favicon.png' }
],
script: [
{
type: 'text/javascript',
src: '/mana.js',
}
]
},
})
And on Nuxt 2.x I used this :
// nuxt.config.js
export default {
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
ssr: false,
// Target: https://go.nuxtjs.dev/config-target
target: 'static'
}
What configuration i should to use on Nuxt 3 to have 'normal' export with an index.html file at the root for all server ?
Please use generate script like yarn generate this will create the .output/public and output will depend on ssr: boolean property in nuxt.config.ts.
if ssr is true which is by default, then there will be individual html for each dynamic route and that means dynamic routes are rendered at build time and whenever there is change in data or number of dynamic routes then you will need to run this command again.
if ssr is false then rendering will be done at client side, like SPA app and dynamic routes will have only one file that will do client side rendering and data will be fetched at client side that way site will show latest data.
Check static-hosting
Static deployment is not currently available for Nuxt 3
Besides adding target: 'static' in your nuxt.config.ts
export default defineNuxtConfig({
target: 'static' // default is 'server'
})
You also need to update your build script to be nuxi generate in your package.json (which was nuxi build originally)
{
"scripts": {
"build": "nuxi generate"
}
}
References: https://v3.nuxtjs.org/bridge/overview#static-target
I managed to deploy my nuxt3 project static to gh-pages. I had to overcome two obstacles.
yarn generate did not generate static routes until I explicitly forced it by setting
generate: {routes: ['/','all','my','other','routes']} ....
in nuxt.config.js as target:"static" did not work for me.
gh-pages need an empty .nojekyll file which seems currently not being generated by nuxt generate nor gh-pages. I entered the following into my package.json:
"deploy": "touch .output/.nojekyll && gh-pages --dotfiles -d .output"
This seems ugly but works for me.

Ionic 5 Capacitor FileTransfer

I'm running in the browser an ionic 5 APP using capacitor and I'm trying to use the file transfer functionality. I follow the documentation https://ionicframework.com/docs/native/file-transfer and configure my app using capacitor. Thus running:
npm install cordova-plugin-file-transfer
npm install #ionic-native/file-transfer
ionic cap sync
In my app.module, I registered the providers:
import { FileTransfer } from '#ionic-native/file-transfer/ngx';
import { File } from '#ionic-native/file/ngx';
...
providers: [
StatusBar,
SplashScreen,
...
FileTransfer,
File
],
Note that I also installed the native file package, so in total I have the following 4 new packages:
"#ionic-native/file": "^5.27.0",
"#ionic-native/file-transfer": "^5.27.0",
"cordova-plugin-file": "^6.0.2",
"cordova-plugin-file-transfer": "^1.7.1",
My code in the component is:
import { Input, Component } from '#angular/core';
import { FileTransfer, FileTransferObject } from '#ionic-native/file-transfer/ngx';
import { File } from '#ionic-native/file/ngx';
#Component({
selector: 'app-order-detail-order-card',
templateUrl: './order-detail-order-card.page.html'
})
export class OrderDetailOrderCardPage {
#Input() pdfUrl: string;
#Input() orderCardId: string;
constructor(private transfer: FileTransfer, private file: File) { }
public downloadFile(): void {
const fileTransfer: FileTransferObject = this.transfer.create();
fileTransfer.download(this.pdfUrl, this.file.applicationDirectory + `${orderCardId}.pdf`).then((entry) => {
console.log('download complete: ' + entry.toURL());
}, (error) => {
// handle error
});
}
}
When I run the app in the browser, I get the following warning and I'm not sure whether the file should donwload somewhere?
common.js:284 Native: tried calling SplashScreen.hide, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator
Even if I don't get the file, I would be expecting to see the "download complete" message. It's not very clear to me as to whether I have to configure something else in my app to be able to run it locally or I have to use this functionality ONLY in either the emulator or the device itself.
What else needs to be configured to get this to work?
common.js:284 Native: tried calling SplashScreen.hide, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator
this means that you are using the browser emulator which doesn't have any splashscreen, you can totally ignore that warning ( you won't get it using a simulator or a real device).
You should paste the html section of that page too, because probably the download doesn't start because an incomplete url and it doesn't proceed with the "then()"
maybe i'm wrong, but it can be possible.

Angular 5 Routing - Navigate to route by typing URL into address bar returns Handler for Request not found (404)

I am using Angular 5 to talk to a Service Stack back end.
I can load my home page by typing in the root address: http://127.0.0.1:8088 and from there I can navigate to all my defined routes using the relevant links.
However if I try to manually type in a route, i.e. http://127.0.0.1:8088/home or http://127.0.0.1:8088/searcharchive I get:
Handler for Request not found (404):
Request.HttpMethod: GET
Request.PathInfo: /home
Request.QueryString: Request.RawUrl: /home
My routing codes is as follows:
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'searcharchive', component: SearchArchiveComponent },
{path: '', redirectTo: 'home', pathMatch: 'full'},
{path: '**', component: PageNotFoundComponent}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
And the HTML template is:
<nav>
<a [routerLink]="['/home']">Home</a>
<br/>
<a [routerLink]="['/searcharchive']">Search Archive</a>
<br>
<div class="container-admin-nav">
<a [routerLink]="['/admin']">Admin Module</a>
</div>
</nav>
This is causing a real headache as not only can I not navigate using the address bar I cannot even do simple things like adding images, as no matter where I place the image It can't be displayed. When looking at the developer tools I get GET http://127.0.0.1:8088/logoTransparent.png 404 (Not Found) so I can only surmise that routing is (once again) getting in the way some how.
I had a similar problem because I was using
proxy configuration.
Angular app was my front-end and I had a SpringBoot app as back-end.
In my proxy.config.json file I had the following:
{
"/**": { <-- **marked line**
"target": {
"host": "localhost",
"protocol": "http:",
"port": 8080
},
"secure": false,
"logLevel": "debug"
}
}
So, whenever I typed in any route in the address bar, it would get rerouted to my SpringBoot app because of the marked line... and I didn't want that. I just wanted my back-end requests from my services to be rerouted to my back-end.
Solution:
I added /api to my back-end requests (in all my services) and then, in proxy.config.json I just removed /api from the url. To achieve this, I just added "pathRewrite": { "^/api": "" }, to my proxy.config.json which now looked like this:
{
"/api/**": {
"target": {
"host": "localhost",
"protocol": "http:",
"port": 8080
},
"pathRewrite": {
"^/api": ""
},
"secure": false,
"logLevel": "debug"
}
}

Angular2 HTTP Request Providers

I want to make connection between my angular app and my REST API.
Here it returns JSON http://is.njn.mvm.bg/check. So my question is which providers do I need because I include in app.module, but it still doesn't work.
import { HttpModule} from '#angular/http';
I am using Angular2 HTTP tutorial
private heroesUrl = 'http://is.njn.mvm.bg/check'; // URL to web API
constructor (private http: Http) {}
getHeroes (): Observable<Hero[]> {
return this.http.get(this.heroesUrl)
.map(this.extractData)
.catch(this.handleError);
}
I am getting XMLHttpRequest cannot load http://localhost:8000/da. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
you are using the http request wrong. plz use following code.
app.component.ts
//our root app component
import { Component } from '#angular/core'
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Component({
selector: 'root',
template: `
<div>
{{people}}
{{ err}}
</div>
`
})
export class App {
people;
err;
constructor(http:Http) {
http.get('http://is.njn.mvm.bg/check').map(res => res.text()).subscribe(people => this.people = people,err=>this.err = err);
// Subscribe to the observable to get the parsed people object and attach it to the
// component
}
}
Also remember
Follow error occur in your console:
Access-control-allow-origin
For remove this error see:
chrome extension for access control
You need to put header parameter "Access-Control-Allow-Origin" in the server's HTTP response. You can't make this work from the client side only. I also had the same issue when trying to grab data from my Java JSON REST server. I am not sure what you use server side, but in Java it looks something like this:
return Response.ok() //200
.header("Access-Control-Allow-Origin", "*");
For information on this error (CORS), see this:
How does Access-Control-Allow-Origin header work?
You also need to add it to imports of #NgModule
#NgModule({
imports: [BrowserModule, HttpModule]
...
})
You module code will be like below:
#NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
],
declarations: [
AppComponent
],
providers: [
{provide: APP_BASE_HREF, useValue: '/'},
],
bootstrap: [AppComponent]
})
export class AppModule {
}
you service code need to similar to this
constructor(private http: Http) {
}
getCountriesByRegion(region: string) {
return this.http.get(this.countries_endpoint_url + region).map(res => res.json());
}
//you can also do like this
getHeroes(): Observable<any[]> {
return this.http.get(this.heroesUrl)
.map(this.extractData)
.catch(this.handleError);
}
You have the Angular app that's served by the server running on port 3000, but this app tries to make HTTP calls to the server running on another port 8000.
You have two options:
1. Deploy your Angular app under the server that runs on port 8000, in which case your Angular app will hit the same port it was served from.
2. Configure a proxy on the server that runs on port 3000 to allow access to port 8000.
For the second scenario, if you use Angular CLI with your project, create a file proxy-conf.json, for example:
{
 "/api": {
 "target": "http://localhost:8000",
 "secure": false
 }
}
Then sevre your Anglar app like this:
ng serve --proxy-config proxy-conf.json

Using Grunt to Mock Endpoints

I'm using Yeoman, Grunt, and Bower, to construct a platform for building a frontend independently of a a backend. The idea would be that all of my (AngularJS) controller, services, factories, etc live in this project, and get injected afterwards into my serverside codebase based off the result of grunt build.
My question is:
How can I mock endpoints so that the Grunt server responds to the same endpoints as my (Rails) App will?
At the moment I am using:
angular.module('myApp', ['ngResource'])
.run(['$rootScope', function ($rootScope) {
$rootScope.testState = 'test';
}]);
And then in each of my individual services:
mockJSON = {'foo': 'myMockJSON'}
And on every method:
if($rootScope.testState == 'test'){
return mockJSON;
}
else {
real service logic with $q/$http goes here
}
Then after grunt build, testState = 'test' gets removed.
This is clearly a relatively janky architecture. How can I avoid it? How can I have Grunt respond to the same endpoints as my app (some of which have dynamic params) apply some logic (if necessary), and serve out a json file (possibly dependent on path params)?
I've fixed this issue by using express to write a server that responds with static json.
First I created a directory in my project called 'api'. Within that directory I have the following files:
package.json:
{
"name": "mockAPI",
"version": "0.0.0",
"dependencies": {
"express": "~3.3.4"
}
}
Then I run npm install in this directory.
index.js:
module.exports = require('./lib/server');
lib/server.js:
express = require('express');
var app = express();
app.get('/my/endpoint', function(req, res){
res.json({'foo': 'myMockJSON'});
});
module.exports = app
and finally in my global Gruntfile.js:
connect: {
options: {
port: 9000,
hostname: 'localhost',
},
livereload: {
options: {
middleware: function (connect, options) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
require('./api')
];
}
}
},
Then the services make the requests, and the express server serves the correct JSON.
After grunt build, the express server is simply replaced by a rails server.
As of grunt-contrib-connect v.0.7.0 you can also just add your custom middleware to the existing middleware stack without having to manually rebuild the existing middleware stack.
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
],
middleware: function(connect, options, middlewares) {
// inject a custom middleware into the array of default middlewares
middlewares.push(function(req, res, next) {
if (req.url !== '/my/endpoint') {
return next();
}
res.writeHead(200, {'Content-Type': 'application/json' });
res.end("{'foo': 'myMockJSON'}");
});
return middlewares;
}
}
},
See https://github.com/gruntjs/grunt-contrib-connect#middleware for the official documentation.
Alternatively you can use the grunt-connect-proxy to proxy everything that is missing in your test server to an actual backend.
It's quite easy to install, just one thing to remember when adding proxy to your livereload connect middleware is to add it last, like this:
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
proxySnippet
];
}
grunt-connect-prism is similar to the Ruby project VCR. It provides an easy way for front end developers to record HTTP responses returned by their API (or some other remote source) and replay them later. It's basically an HTTP cache, but for developers working on a Single Page Application (SPA). You can also generate stubs for API calls that don't exist, and populate them the way you want.
It's useful for mocking complex & high latency API calls during development. It's also useful when writing e2e tests for your SPA only, removing the server from the equation. This results in much faster execution of your e2e test suite.
Prism works by adding a custom connect middleware to the connect server provided by the grunt-contrib-connect plugin. While in 'record' mode it will generate a file per response on the filesystem with content like the following:
{
"requestUrl": "/api/ponies",
"contentType": "application/json",
"statusCode": 200,
"data": {
"text": "my little ponies"
}
}
DISCLAIMER: I'm the author of this project.
You can use Apache proxy and connect your REST server with gruntjs.
Apache would do this:
proxy / -> gruntjs
proxy /service -> REST server
you would use your application hitting Apache and angular.js application would think that is talking with itself so no cross domain problem.
Here is a great tutorial on how to set this up:
http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/
Just my alternative way that based on Abraham P's answer. It does not need to install express within 'api' folder. I can separate the mock services for certain files. For example, my 'api' folder contains 3 files:
api\
index.js // assign all the "modules" and then simply require that.
user.js // all mocking for user
product.js // all mocking for product
file user.js
var user = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'role' : 'admin'
})
);
}
else {
next();
}
}
module.exports = user;
file product.js
var product = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'name' : 'test',
'category': 'test'
})
);
}
else {
next();
}
}
module.exports = product;
index.js just assigns all the "modules" and we simply require that.
module.exports = {
product: require('./product.js'),
user: require('./user.js')
};
My Gruntfile.js file
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app),
require('./api').user,
require('./api').product,
];
}
}
}