I want to select an image and POST that to the Django REST API that I have built but I am getting an error in doing so
""product_image": ["The submitted data was not a file. Check the encoding type on the form."]"
I can create and update strings and integers but when I try add the image field I get this error. I can POST images through Postman so I don't think its my API that's at fault.
Can anyone help me out here as I have looked around but can't seem to find anything.
add-product.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { ActivatedRoute, Router } from '#angular/router';
import { ApiService } from 'src/app/api.service';
import { Product } from 'src/app/models/Product';
import { Location } from '#angular/common';
import { Shop } from '../../../models/Shop';
#Component({
selector: 'app-add-product',
templateUrl: './add-product.component.html',
styleUrls: ['./add-product.component.css']
})
export class AddProductComponent implements OnInit {
product!: Product;
selectedFile!: File;
colours = [
'Red',
'Blue',
'Orange',
'Yellow',
'White',
'Black',
'Navy',
'Brown',
'Purple',
'Pink'
]
categories = [
'Food & Beverages',
'Clothing & Accessories',
'Home & Garden',
'Health & Beauty',
'Sports & Leisure',
'Electronic & Computing'
]
stock = [
'In Stock',
'Out Of Stock',
]
productForm = new FormGroup({
name: new FormControl(''),
price: new FormControl(0.00),
product_image: new FormControl(''),
product_description: new FormControl(''),
quantity: new FormControl(0),
colour: new FormControl(''),
stock: new FormControl(''),
shipping_fee: new FormControl(0.00),
weight: new FormControl(0.00),
shop: new FormControl(''),
category: new FormControl(''),
});
constructor(
private route: ActivatedRoute,
private apiService: ApiService,
private location: Location,
private router: Router,
private postService: ApiService
) { }
ngOnInit(): void {
}
goBack(): void {
this.location.back();
}
onFileSelected(event: any) {
this.selectedFile = <File>event.target.files[0]
console.log(event)
}
addProduct(): void {
console.log(this.productForm.value)
this.apiService.addProduct(
this.productForm.value
).subscribe(() => this.goBack(),
result => console.log(result),
);
}
}
add-product.component.html
<form [formGroup]="productForm">
<label>Product Name</label><br>
<input type="text" formControlName="name"><br>
<label>Price</label><br>
<input type="text" formControlName="price"/><br>
<input type="file" formControlName="product_image" (change)="onFileSelected($event)"><br>
<label>Description</label><br>
<textarea type="text" formControlName="product_description"></textarea><br>
<label>Quantity of Products</label><br>
<input type="text" formControlName="quantity"/><br>
<label>Colour of Product</label><br>
<select formControlName="colour">
<option value="" disabled>Choose a Colour</option>
<option *ngFor="let colour of colours" [ngValue]="colour">
{{ colour }}
</option>
</select><br>
<label>Stock Availability</label><br>
<select formControlName="stock">
<option value="" disabled>Stock Availability</option>
<option *ngFor="let stock of stock" [ngValue]="stock">
{{ stock }}
</option>
</select><br>
<label>Shipping Fee Price</label><br>
<input type="text" formControlName="shipping_fee"/><br>
<label>Weight (kg)</label><br>
<input type="text" formControlName="weight"/><br>
<label>Shop</label><br>
<input type="text" formControlName="shop"/><br>
<label>Category</label><br>
<select formControlName="category">
<option value="" disabled>Choose a Category</option>
<option *ngFor="let category of categories" [ngValue]="category">
{{ category }}
</option>
</select><br>
</form>
<button type="submit" (click)="addProduct()">Add</button>
<button (click)="goBack()">go back</button>
api.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http'
import { Product } from './models/Product';
import { CookieService } from 'ngx-cookie-service';
import { Category } from './models/Category';
import { Shop } from './models/Shop';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ApiService {
baseUrl = 'http://127.0.0.1:8000/';
baseProductUrl = `${this.baseUrl}app/products/`
baseCategoryUrl = `${this.baseUrl}app/categories/`
baseShopUrl = `${this.baseUrl}app/shops/`
headers = new HttpHeaders({
'Content-Type': 'application/json',
});
constructor(
private httpClient: HttpClient,
private cookieService: CookieService,
) { }
/* Product CRUD */
/* POST: add a product to the server */
addProduct(product: Product) {
const productUrl = `${this.baseProductUrl}`
return this.httpClient.post<Product>(productUrl, product, {headers: this.getAuthHeaders()})
}
// DELETE: delete the product from the server
deleteProduct(product_code: number): Observable<Product> {
const productUrl = `${this.baseProductUrl}${product_code}/`
return this.httpClient.delete<Product>(productUrl, {headers: this.getAuthHeaders()})
}
// PUT: update the product on the server
updateProduct(product_code: number, product: Product): Observable<Product> {
const productUrl = `${this.baseProductUrl}${product_code}/`
return this.httpClient.put<Product>(productUrl, product, {headers: this.getAuthHeaders()})
}
// GET: get all products from the server
getProducts() {
return this.httpClient.get<Product[]>(this.baseProductUrl, {headers: this.getAuthHeaders()});
}
// GET: get one product from the server
getProduct(product_code: number): Observable<Product> {
const productUrl = `${this.baseProductUrl}${product_code}/`
return this.httpClient.get<Product>(productUrl, {headers: this.getAuthHeaders()});
}
// GET: get all categories from the server
getCategories() {
return this.httpClient.get<Category[]>(this.baseCategoryUrl, {headers: this.getAuthHeaders()});
}
// GET: get one category from the server
getCategory(id: number): Observable<Category> {
const url = `${this.baseCategoryUrl}${id}/`;
return this.httpClient.get<Category>(url, {headers: this.getAuthHeaders()});
}
// GET: get all shops from the server
getShops() {
return this.httpClient.get<Shop[]>(this.baseShopUrl, {headers: this.getAuthHeaders()});
}
// GET: get one shop from the server
getShop(business_reg: string): Observable<Shop> {
const url = `${this.baseShopUrl}${business_reg}/`;
return this.httpClient.get<Shop>(url, {headers: this.getAuthHeaders()});
}
loginUser(authData: any) {
const body = JSON.stringify(authData);
return this.httpClient.post(`${this.baseUrl}auth/`, body, {headers: this.headers});
}
registerUser(authData: any) {
const body = JSON.stringify(authData);
return this.httpClient.post(`${this.baseUrl}user/users/`, body, {headers: this.headers});
}
getAuthHeaders() {
const token = this.cookieService.get('ur-token')
return new HttpHeaders({
'Content-Type': 'application/json',
Authorization: `Token ${token}`
});
}
}
The content-type must be multipart/form-data instead of application-json
that way you can send files to an API
Related
I am new to and currently working on a Django and Angular webapp and I cant seem to be able to create and update my products from the angular web app and send them to the REST API to update the server. I have written a delete function and service request that works and I can retrieve the products from the API but I don't know how to write the functions for create products and update products. Would anyone be able to help me here?
Here is what I have so far:
api.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http'
import { Product } from './models/Product';
import { CookieService } from 'ngx-cookie-service';
import { Category } from './models/Category';
import { Shop } from './models/Shop';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ApiService {
baseUrl = 'http://127.0.0.1:8000/';
baseProductUrl = `${this.baseUrl}app/products/`
baseCategoryUrl = `${this.baseUrl}app/categories/`
baseShopUrl = `${this.baseUrl}app/shops/`
headers = new HttpHeaders({
'Content-Type': 'application/json',
});
constructor(
private httpClient: HttpClient,
private cookieService: CookieService,
) { }
/* Product CRUD */
/* ADD: add a product to the server */
addProduct(): Observable<Product> {
const productUrl = `${this.baseProductUrl}`
return this.httpClient.post<Product>(productUrl, {headers: this.getAuthHeaders()})
}
// DELETE: delete the product from the server
deleteProduct(product_code: number): Observable<Product> {
const productUrl = `${this.baseProductUrl}${product_code}/`
return this.httpClient.delete<Product>(productUrl, {headers: this.getAuthHeaders()})
}
// PUT: update the product on the server
updateProduct(product_code: Product): Observable<any> {
const productUrl = `${this.baseProductUrl}${product_code}/`
return this.httpClient.put(productUrl, {headers: this.getAuthHeaders()})
}
// GET: get all products from the server
getProducts() {
return this.httpClient.get<Product[]>(this.baseProductUrl, {headers: this.getAuthHeaders()});
}
// GET: get one product from the server
getProduct(product_code: number): Observable<Product> {
const productUrl = `${this.baseProductUrl}${product_code}/`
return this.httpClient.get<Product>(productUrl, {headers: this.getAuthHeaders()});
}
// GET: get all categories from the server
getCategories() {
return this.httpClient.get<Category[]>(this.baseCategoryUrl, {headers: this.getAuthHeaders()});
}
// GET: get one category from the server
getCategory(id: number): Observable<Category> {
const url = `${this.baseCategoryUrl}${id}/`;
return this.httpClient.get<Category>(url, {headers: this.getAuthHeaders()});
}
// GET: get all shops from the server
getShops() {
return this.httpClient.get<Shop[]>(this.baseShopUrl, {headers: this.getAuthHeaders()});
}
// GET: get one shop from the server
getShop(business_reg: string): Observable<Shop> {
const url = `${this.baseShopUrl}${business_reg}/`;
return this.httpClient.get<Shop>(url, {headers: this.getAuthHeaders()});
}
loginUser(authData: any) {
const body = JSON.stringify(authData);
return this.httpClient.post(`${this.baseUrl}auth/`, body, {headers: this.headers});
}
registerUser(authData: any) {
const body = JSON.stringify(authData);
return this.httpClient.post(`${this.baseUrl}user/users/`, body, {headers: this.headers});
}
getAuthHeaders() {
const token = this.cookieService.get('ur-token')
return new HttpHeaders({
'Content-Type': 'application/json',
Authorization: `Token ${token}`
});
}
}
dashboard.component.ts
import { Component, OnInit } from '#angular/core';
import { Product } from 'src/app/models/Product';
import { CookieService } from 'ngx-cookie-service';
import { Router } from '#angular/router';
import { ApiService } from '../../api.service';
import { Category } from '../../models/Category';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
products: Product[] =[]
constructor(
private cookieService: CookieService,
private router: Router,
private apiService: ApiService
) { }
ngOnInit(): void {
this.getProducts()
}
getProducts(): void {
const urToken = this.cookieService.get('ur-token')
if (!urToken) {
this.router.navigate(['/auth']);
} else {
this.apiService.getProducts().subscribe(
data => {
this.products = data;
console.log('selectedProduct', this.products);
},
error => console.log(error)
);
}
}
delete(product: Product): void {
this.products = this.products.filter(h => h !== product);
this.apiService.deleteProduct(product.product_code).subscribe();
}
}
dashboard.component.html
<section>
<div class="container">
<h1>My Dashboard <button class="btn" routerLink="add/">Add Product</button></h1>
<div class="card-wrapper">
<div class="card" *ngFor="let product of products">
<!-- card left -->
<div class="product-content">
<img class="img-fluid image" src="{{product.product_image}}">
<div class="product-item">
<h2 class="product-title">{{ product.name }}</h2>
<a class="edit"><button class="btn" routerLink="edit/{{ product.product_code }}">Edit</button></a>
<a class="delete"><button class="btn" (click)="delete(product)">Delete</button></a>
</div>
</div>
</div>
</div>
</div>
</section>
product-form.component.ts
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { ApiService } from 'src/app/api.service';
import { Product } from 'src/app/models/Product';
import { Location } from '#angular/common';
import { FormGroup, FormControl } from '#angular/forms';
#Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.css']
})
export class ProductFormComponent implements OnInit {
product!: Product;
constructor(
private route: ActivatedRoute,
private apiService: ApiService,
private location: Location
) { }
ngOnInit(): void {
this.getProduct()
}
getProduct(): void {
const product_code = Number(this.route.snapshot.paramMap.get('product_code'));
this.apiService.getProduct(product_code)
.subscribe(product => this.product = product);
}
goBack(): void {
this.location.back();
}
save(): void {
this.apiService.updateProduct(this.product)
.subscribe(() => this.goBack());
}
}
product-form.component.html
<div *ngIf="product">
<input id="product-code" [(ngModel)]="product.product_code" placeholder="product_code">
<input id="product-name" [(ngModel)]="product.name" placeholder="name">
<input id="product-price" [(ngModel)]="product.price" placeholder="price">
</div>
Looking at your API service the HTTP POST and PUT calls are missing payload data.
Can you try passing the data for your product as a parameter?
The product code for the PUT should be in a class with populated data (from your component) so that your backend API can pick up the code (and other product data fields) and update your data. Your backend API methods should then read the request data from the body (the payload).
For your Angular API service methods you should pass product data parameters from your component as follows:
/* ADD: add a product to the server */
addProduct(product: Product): Observable {
const productUrl = ${this.baseProductUrl}
return this.httpClient.post(productUrl, product, {headers: this.getAuthHeaders()})
}
// PUT: update the product on the server
updateProduct(product: Product): Observable {
const productUrl = ${this.baseProductUrl}${product_code}/
return this.httpClient.put(productUrl, product {headers: this.getAuthHeaders()})
}
There is a post (https://andrewhalil.com/2020/12/01/calling-web-apis-from-your-angular-ui/) on my site that shows how this is done in Angular.
i trying to post data from ant design React.js into Python Django rest frame work.
so I am using method OnFinish to send data, but its not working.
MY big problem is , i don't know how can i Introduction Data i want to send them data from Form , by using React-redux or something else way , so please Help me .
#react.js Form:
import React, { Component } from "react";
import {
Form,
Input,
Button,
PageHeader,
Select,
DatePicker,
message,
} from "antd";
import "antd/dist/antd.css";
import { connect } from "react-redux";
import axios from "axios";
// defualt setting for django
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
// from layout setting
const formItemLayout = {
labelCol: {
xs: {
span: 24,
},
sm: {
span: 8,
},
},
wrapperCol: {
xs: {
span: 24,
},
sm: {
span: 16,
},
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
offset: 0,
},
sm: {
span: 16,
offset: 8,
},
},
};
// end fform layout setting
// const onFinish = (values) => {
// console.log(values);
// axios.post("http://127.0.0.1:8000/api/create/", {
// title: values.title,
// manager: values.manager,
// });
// };
// const title = event.target.elements.title.value;
// const manager = event.target.elements.manager.value;
class ExtrashiftForm extends React.Component {
constructor(props) {
super(props);
this.state = {
Extrashifts: [],
};
}
// componentDidMount() {
// this.fetchExtrashift();
// }
handleSubmit = () => {
axios
.post("http://127.0.0.1:8000/api/create", {
data: {
title: this.target.elements.title.value,
manager: this.data.item.manager,
},
})
.then((res) => {
if (res.status == 200) message.success("data successfully updated!");
this.fetchExtrashift();
})
.catch((err) => {
message.error("data profile failed to update ...");
});
};
render() {
return (
<div>
<Form {...formItemLayout} name="update">
<Form.Item label="Title :">
<Input name="title" placeholder="Put a title here" />
</Form.Item>
<Form.Item label="Manager :">
<Input name="manager" placeholder="Enter manager name" />
</Form.Item>
<Form.Item {...tailFormItemLayout}>
<Button
type="primary"
htmlType="submit"
onFinish={this.handleSubmit}
>
create
</Button>
</Form.Item>
</Form>
</div>
);
}
}
export default ExtrashiftForm;
#back end api/urls.py :
from Extrashift.api.views import ExtrashiftViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', ExtrashiftViewSet, basename='Extrashift')
urlpatterns = router.urls
#backend : api/views.py:
from rest_framework import viewsets
from Extrashift.models import Extrashift
from .Serializers import ExtrashiftSerializers
class ExtrashiftViewSet(viewsets.ModelViewSet):
serializer_class = ExtrashiftSerializers
queryset = Extrashift.objects.all()
from rest_framework import permissions
from rest_framework.generics import (
ListAPIView,
RetrieveAPIView,
CreateAPIView,
UpdateAPIView,
DestroyAPIView
)
from my back end everything is work but Please help me to i can send only one data from this form.
if is possible please ,change my Code to the Correct code
Nothing spectacular here, you can read the docs
Rather than giving the name as a prop to the Input field.
I've passed it as a prop to Form.Item component
You can check the example here
import React, { Component } from "react";
import {
Form,
Input,
Button,
PageHeader,
Select,
DatePicker,
message,
} from "antd";
import "antd/dist/antd.css";
import axios from "axios";
// defualt setting for django
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
// from layout setting
const formItemLayout = {
labelCol: {
xs: {
span: 24,
},
sm: {
span: 8,
},
},
wrapperCol: {
xs: {
span: 24,
},
sm: {
span: 16,
},
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
offset: 0,
},
sm: {
span: 16,
offset: 8,
},
},
};
// end fform layout setting
// const onFinish = (values) => {
// console.log(values);
// axios.post("http://127.0.0.1:8000/api/create/", {
// title: values.title,
// manager: values.manager,
// });
// };
// const title = event.target.elements.title.value;
// const manager = event.target.elements.manager.value;
export default class ExtrashiftForm extends React.Component {
constructor(props) {
super(props);
this.state = {
Extrashifts: [],
};
}
// componentDidMount() {
// this.fetchExtrashift();
// }
handleSubmit = (values) => {
console.log(values)
// axios
// .post("http://127.0.0.1:8000/api/create", {
// data: {
// title: this.target.elements.title.value,
// manager: this.data.item.manager,
// },
// })
// .then((res) => {
// if (res.status == 200) message.success("data successfully updated!");
// this.fetchExtrashift();
// })
// .catch((err) => {
// message.error("data profile failed to update ...");
// });
};
render() {
return (
<div>
<Form {...formItemLayout} name="update" onFinish={this.handleSubmit}>
<Form.Item label="Title :" name="title">
<Input placeholder="Put a title here" />
</Form.Item>
<Form.Item label="Manager :" name="manager">
<Input placeholder="Enter manager name" />
</Form.Item>
<Form.Item {...tailFormItemLayout}>
<Button
type="primary"
htmlType="submit"
>
create
</Button>
</Form.Item>
</Form>
</div>
);
}
}
i create Rest API for login in Django and i want to call it in angular4
heare is my angular4 code
login.components.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Http, Response, Headers} from '#angular/http';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private router:Router, private http:Http) { }
getData = [];
with this function i get data from my APIand i am trying to compare this data with form data
fatchData = function(){
this.http.get("http://127.0.0.1:8000/loginAdmin/").subscribe((res:Response) => {
this.getData = res.json();
})
}
loginUser(e){
e.preventDefault();
var username = e.target.elements[0].value;
var password = e.target.elements[1].value;
if(username == 'this.getData.username' && password == 'this.getData.password')
{
this.router.navigate(['/deshbord'])
}
else{
console.log('Error Find');
}
}
ngOnInit() {
this.fatchData();
}
}
this is my login.comonents.login i want that when user give user name and password its compare with my API data and it's true then navigate to other page..
<form (submit)="loginUser($event)">
<div class="input">
<label>UserName</label>
<input type="text">
</div>
<div class="input">
<label>password</label>
<input type="password">
</div>
<div class="input">
<input type="submit" value="Login">
</div>
</form>
I have an ionic 2 app and am using native FB Login to retrieve name/pic and saving it to NativeStorage. The flow is that I open WelcomePage, log in, and save the data. From there, navPush to HomePage. So far it works great.
However, I have a ProfilePage (accessible via tabRoot), the fails. The reason is that in my profile.html I have the following tag that should render Username (this works on HomePage, but not on ProfilePage):
{{ user.name }}
The error I get on XCode is:
2017-05-02 18:40:41.657374 FoxBox App[1102:226159] ERROR: Failed to navigate: undefined is not an object (evaluating 'co.user.picture')
Note that for some reason it prepends it with 'co.' which I have no idea where its coming from or what it means.
Here is the WelcomePage code:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { HomePage } from '../home/home';
import { AboutPage } from '../about/about';
import { Facebook, NativeStorage } from 'ionic-native';
//import { FacebookAuth, User, Auth } from '#ionic/cloud-angular';
import { CloudSettings, CloudModule } from '#ionic/cloud-angular';
import {GoogleAnalytics} from 'ionic-native';
#Component({
selector: 'page-welcome',
templateUrl: 'welcome.html'
})
export class WelcomePage {
FB_APP_ID: number = 1234567890;
homePage = HomePage;
aboutPage = AboutPage;
constructor(
public navCtrl: NavController,
//public facebookAuth: FacebookAuth,
//public auth: Auth,
//public user: User,
) {
Facebook.browserInit(this.FB_APP_ID, "v2.8");
}
doFbLogin(){
//alert("fb is logged in");
let permissions = new Array();
let nav = this.navCtrl;
//the permissions your facebook app needs from the user
permissions = ["public_profile"];
Facebook.login(permissions)
.then(function(response){
let userId = response.authResponse.userID;
let params = new Array();
//Getting name and gender properties
Facebook.api("/me?fields=name,gender", params)
.then(function(user) {
user.picture = "https://graph.facebook.com/" + userId + "/picture?type=large";
//now we have the users info, let's save it in the NativeStorage
NativeStorage.setItem('user',
{
name: user.name,
gender: user.gender,
picture: user.picture,
email: user.email,
})
.then(function(){
nav.push(HomePage);
console.log("User Data Stored");
}, function (error) {
console.log(error);
})
})
}, function(error){
console.log(error);
});
}
}
Here is the HomePage code:
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import { ClaimPage } from '../claim/claim';
import { SocialSharing } from '#ionic-native/social-sharing';
import { Facebook, NativeStorage } from 'ionic-native';
//import { FacebookAuth, User, Auth } from '#ionic/cloud-angular';
import { CloudSettings, CloudModule } from '#ionic/cloud-angular';
import {GoogleAnalytics} from 'ionic-native';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
posts: any;
sendme: any;
claimPage = ClaimPage;
user: any;
userReady: boolean = false;
constructor(
public navCtrl: NavController,
public http: Http,
private sharingVar: SocialSharing,
public platform: Platform,
) {
// Check to see if user already exists (via FB login)
let env = this;
NativeStorage.getItem('user')
.then(function (data){
env.user = {
name: data.name,
gender: data.gender,
picture: data.picture
};
env.userReady = true;
// console.log(data.name);
}, function(error){
console.log(error);
});
this.platform.ready().then(() => {
//alert("platform is ready");
GoogleAnalytics.trackView("Home-Page", "http://foxboxapp.com/home", true);
//alert("GA called");
});
this.http.get('http://getyourtryston.com/foox/sample.php').map(res => res.json()).subscribe(data => {
this.posts = data.data.children;
});
}
otherShare(){
this.sharingVar.share("FoxBox App","Get Awesome College Deals",null/*File*/,"http://fooxsocial.com")
.then(()=>{
//alert("Success");
},
()=>{
alert("Sharing Failed!")
})
}
}
And here is the ProfilePage code which fails:
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
import { WelcomePage } from '../welcome/welcome';
import {GoogleAnalytics} from 'ionic-native';
import { SocialSharing } from '#ionic-native/social-sharing';
import { Facebook, NativeStorage } from 'ionic-native';
//import { FacebookAuth, User, Auth } from '#ionic/cloud-angular';
//import { CloudSettings, CloudModule } from '#ionic/cloud-angular';
#Component({
selector: 'page-about',
templateUrl: 'about.html'
})
export class AboutPage {
user: any;
userReady: boolean = false;
constructor(
public navCtrl: NavController,
public platform: Platform,
private sharingVar: SocialSharing,
//public facebookAuth:FacebookAuth,
//public auth:Auth,
) {
// Check to see if user already exists (via FB login)
let env = this;
NativeStorage.getItem('user')
.then(function (data){
env.user = {
name: data.name,
gender: data.gender,
picture: data.picture
};
env.userReady = true;
// console.log(data.name);
}, function(error){
console.log(error);
});
// PLATFORM READY, do your thang!
this.platform.ready().then(() => {
// Ping Google Analytics
GoogleAnalytics.trackView("Profile Page", "http://foxboxapp.com/home", true);
});
}
otherShare(){
this.sharingVar.share("FOOX Social App","Get Awesome College Deals",null/*File*/,"http://fooxsocial.com")
.then(()=>{
//alert("Success");
},
()=>{
alert("Sharing Failed!")
})
}
doFbLogout(){
var nav = this.navCtrl;
Facebook.logout()
.then(function(response) {
//user logged out so we will remove him from the NativeStorage
NativeStorage.remove('user');
nav.push(WelcomePage);
}, function(error){
console.log(error);
});
}
}
And here is ProfilePage.html
<ion-header>
<ion-navbar color="light" hideBackButton="true">
<ion-buttons end>
<button ion-button icon-only (click)="otherShare()">
<ion-icon name="share"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ion-card class="pCard">
<div class="pHeader" align="center">
<div *ngIf="user" class="pImgBox" align="center">
<img class="pImage" src="{{ user.picture }}">
</div>
<div class="pUsername" align="center">
<div *ngIf="user"> {{user.name}} </div>
<br>
<span class="pSchool">(Santa Monica College)</span>
</div>
</div>
<ion-list>
<ion-item class="pItems">
Share App
</ion-item>
<ion-item class="pItems">
Give Us Feedback
</ion-item>
<ion-item class="pItems">
Suggest Vendors
</ion-item>
<ion-item class="pItems">
Privacy & Terms of Service
</ion-item>
<ion-item class="pItems">
Log Out
</ion-item>
<ion-item class="pItems">
Delete Account
</ion-item>
</ion-list>
</ion-card>
<button ion-button round (click)="doFbLogout()">Log Out</button>
</ion-content>
I should mention that, if I remove {{ user.name }} and {{ user.picture }} from my ProfilePage.html, there does NOT seem to be any problems. In fact, if you notice in the ts of ProfilePage, I can both Alert and Console.log the username (data.name) without any issues.
I'm a beginner and would appreciate any concise help in this regard. Thank you.
I finally found a solution. In the html file (ProfilePage.html), I used an *ngIf conditional:
<div *ngIf="user"> {{user.name}} </div>
This will introduce a delay such that the 'user' object is no longer null as it reads from NativeStorage.
Alternatively, an Elvis Operator also works for me:
<div> {{ user?.name }} </div>
I am trying to make an website that connets with a weather api and gets some info about current weather in given city. When i looked at network flow in my application i do recive a json that contais that information but i cannot map it and display results. Error i revice is :
TypeError: response.json(...).map is not a function WeatherSearchComponent.ts:138
at MapSubscriber.project (WeatherSearchComponent.ts:84)
at MapSubscriber._next (map.js:77)
at MapSubscriber.Subscriber.next (Subscriber.js:89)
at XMLHttpRequest.onLoad (http.umd.js:1083)
at ZoneDelegate.invokeTask (zone.js:225)
at Object.onInvokeTask (core.umd.js:6004)
at ZoneDelegate.invokeTask (zone.js:224)
at Zone.runTask (zone.js:125)
at XMLHttpRequest.ZoneTask.invoke (zone.js:293)
Heres WeatherSearchComponent:
import {
Component,
Injectable,
OnInit,
ElementRef,
EventEmitter,
Inject
} from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs';
import 'rxjs/Rx';
import 'rxjs/add/operator/map';
export var WEATHER_API_KEY: string = 'api_key';
export var WEATHER_API_URL: string ='http://api.openweathermap.org/data/2.5/weather';
export var GDANSK_ID: string = '3099434';
/*let loadingGif: string = ((<any>window).__karma__) ? '' :
require('images/loading.gif');*/
class SearchResult {
content: string;
constructor(obj?: any) {
this.content= obj && obj.content ||
WEATHER_API_URL + 'id=' + obj.city + 'appid=' + WEATHER_API_KEY;
}
}
// http://api.openweathermap.org/data/2.5/weather?
// id=3099434&appid=api_key
#Injectable()
export class WeatherService {
constructor(private http: Http,
#Inject(WEATHER_API_KEY) private apiKey: string,
#Inject(WEATHER_API_URL) private apiUrl: string) {
}
search(city: string): Observable<SearchResult[]> {
let params: string = [
`q=${city}`,
`appid=${this.apiKey}`
].join('&');
let queryUrl: string = `${this.apiUrl}?${params}`;
console.log("query url" , queryUrl);
var getRequest = this.http.get(queryUrl);
console.log("getRequest", getRequest);
return getRequest
.map((response: Response) => {
return (<any>response.json()).map(item => {
console.log("raw item", item); // uncomment if you want to debug
return new SearchResult({
content: item.main.temp
});
});
});
}
}
export var weatherServiceInjectables: Array<any> = [
{provide: WeatherService, useClass: WeatherService},
{provide: WEATHER_API_KEY, useValue: WEATHER_API_KEY},
{provide: WEATHER_API_URL, useValue: WEATHER_API_URL}
];
/**
* SearchBox displays the search box and emits events based on the results
*/
#Component({
outputs: ['loading', 'results'],
selector: 'search-box',
template: `
<input type="text" class="form-control" placeholder="Search" autofocus>
`
})
export class SearchBox implements OnInit {
loading: EventEmitter<boolean> = new EventEmitter<boolean>();
results: EventEmitter<SearchResult[]> = new EventEmitter<SearchResult[]> ();
constructor(private weather: WeatherService,
private el: ElementRef) {
}
ngOnInit(): void {
// convert the `keyup` event into an observable stream
var observable =
Observable.fromEvent(this.el.nativeElement, 'keyup');
observable
.map((e: any) => e.target.value) // extract the value of the input
.filter((text: string) => text.length > 1) // filter out if empty
.debounceTime(250) // only once every 250ms
.do(() => this.loading.next(true)) // enable loading
// search, discarding old events if new input comes in
.map((query: string) => this.weather.search(query))
.switch()
// act on the return of the search
.subscribe(
(results: SearchResult[]) => { // on sucesss
this.loading.next(false);
this.results.next(results);
},
(err: any) => { // on error
console.log(err);
this.loading.next(false);
},
() => { // on completion
this.loading.next(false);
}
);
}
}
#Component({
inputs: ['result'],
selector: 'search-result',
template: `
<div class="col-sm-6 col-md-3">
<div class="thumbnail">
<img src="{{result.thumbnailUrl}}">
<div class="caption">
<h3>{{result}}</h3>
<p>{{result}}</p>
<p><a href="{{result.videoUrl}}"
class="btn btn-default" role="button">Watch</a></p>
</div>
</div>
</div>
`
})
export class SearchResultComponent {
result: SearchResult;
}
#Component({
selector: 'weather-search',
template: `
<div class='container'>
<div class="page-header">
<h1>Weather Search</h1>
</div>
<div class="row">
<div class="input-group input-group-lg col-md-12">
<search-box
(loading)="loading = $event"
(results)="updateResults($event)"
></search-box>
</div>
</div>
<div class="row">
<search-result
*ngFor="let result of results"
[result]="result">
</search-result>
</div>
</div>
`
})
export class WeatherSearchComponent {
results: SearchResult[];
updateResults(results: SearchResult[]): void {
this.results = results;
// console.log("results:", this.results); // uncomment to take a look
}
}
This is what i do recive from api call :
/*
{"coord":{"lon":18.65,"lat":54.35},
"weather":[{"id":801,"main":"Clouds",
"description":"few clouds","icon":"02n"}],"base":"stations",
"main":{"temp":270.15,"pressure":1035,"humidity":92,
"temp_min":270.15,"temp_max":270.15},"visibility":10000,
"wind":{"speed":2.1,"deg":290},"clouds":{"all":20},
"dt":1484665200,
"sys":{"type":1,"id":5349,"message":0.0029,
"country":"PL","sunrise":1484636080,"sunset":1484665040},"
id":3099434,"name":"Gdansk","cod":200}
*/
It's not clear from your question whether you're trying to .map() on a variable or on an observable.
Scenario #1: variable.map()
variable must be an array. Looks from your code that your variable contains an object.
const jsonData = {
"coord":{"lon":18.65,"lat":54.35},
// Abridged for brevity...
id":3099434,"name":"Gdansk","cod":200
};
jsonData.map(...); // WON'T WORK - `jsonData` must be an array
Scenario #2: observable.map()
You must import the map operator in your code before mapping:
import 'rxjs/add/operator/map';
// Then, later
Observable.map(...);