How To Pagination Angular2 with Django Rest Framework API - python

I am trying to create a simple blog application using Angular2 with Django Rest Framework.
I am implementing pagination in Django, but I do not know how to rendering it in Angular.
API has the following structure.
Entries are paginated every 5 entries.
ng2app/src/app/models/entries.model.ts
export interface IEntries {
count: any,
next: any,
previous: any,
results: IResults[]
}
export interface IResults {
title: string,
body: string,
created_at: any,
updated_at: any
}
ng2app/src/app/services/entries.service.ts
import { Injectable } from "#angular/core";
import { Http } from "#angular/http";
import 'rxjs/add/operator/toPromise';
import { IEntries } from '../models/entries.model';
#Injectable()
export class EntriesService {
constructor(
private http: Http
){
}
getEntries(page: number){
return this.http
.get(`http://127.0.0.1:8000/api/entries/?limit=5&offset=` +((page * 5)-5))
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}
private handleError(error: any) {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
ng2app/src/app/services/entries.component.ts
import { Component, OnInit } from '#angular/core';
import { EntriesService } from '../services/entries.service';
import { IEntries } from '../models/entries.model';
#Component({
selector: 'my-entries',
templateUrl: '../templates/entries.component.html',
styleUrls: ['../static/entries.component.css']
})
export class EntriesComponent implements OnInit{
title = 'entries';
entries: IEntries[] = [];
error: any;
public constructor(
private entriesService: EntriesService,
){}
getEntires(page :number) {
this.entriesService
.getEntries(page)
.then(entries => this.entries = entries)
.catch(error => this.error = error);
}
ngOnInit() {
this.getEntires(1);
}
}
ng2app/src/app/templates/entries.component.html
<div class="container">
<h2>{{title}}</h2>
<div class="panel panel-default" *ngFor="let results of entries.results">
<div class="panel-heading">{{ results.title }}</div>
<div class="panel-body pre-wrap" ng-bind="multiLineText">{{ results.body }}</div>
<div class="panel-footer">{{ results.created_at | date}}</div>
</div>
<nav *ngIf="entries.count > 5">
(I want to display pagination here)
</nav>
</div>
In such a case, please help how to implement Pagination.

After implementing pagination in the Django backend, querying the backend would return results in the following format:
"data": {
"count": ,
"next": "",
"previous": "",
"results": []
}
count: The total number of items returned.
next: The URL to the next items after performing pagination
previous: The URL to the previous items after you have navigated to the next. set of items
results: The items requested for from the backend, paginated obviously i.e if pagination was set to 10 items and 15 were returned, results would return 10 items on the first request, then after navigating to the URL in next, results would return the remaining 5.
Service
#Injectable({
providedIn: "root"
})
export class OurService {
constructor(private http: HttpClient) {}
// Here,we make our request to the backend API, this observer takes in the backend
// api url as a parameter and performs a GET request
getAllTransactions(APIUrl: string): Observable<any> {
return this.http.get<>(APIUrl);
}
}
Component
#Component({
selector: "app-transactions",
templateUrl: "./transactions.component.html",
styleUrls: ["./transactions.component.scss"]
})
export class TransactionsComponent implements OnInit {
transactions: Transacton[];
transactionsUrl = "http://.../api/v1/transactions/"; //url to query for the transactions
next: string;
previous: string;
constructor(private transactionService: TransactionService) {}
ngOnInit(): void {
// On component initialization, load the transactions on the page
this.getTransactions(this.transactionsUrl);
}
getTransactions(url: string) {
this.transactionService.getAllTransactions(url).subscribe(res => {
this.transactions = res.data.results;
if (res.data.next) {
// set the components next transactions here from the response
this.next = res.data.next;
}
if (res.data.previous) {
// set the components previous transactions here from the response
this.previous = res.data.previous;
}
});
}
// function fetches the next paginated items by using the url in the next transactions
fetchNext() {
this.getTransactions(this.next);
}
// function fetches the previous paginated items by using the url in the previous transactions
fetchPrevious() {
this.getTransactions(this.previous);
}
HTML
<div class="page-buttons">
<button class="btn prev" (click)="fetchPrevious()">
</button>
<button class="btn next" (click)="fetchNext()">
</button>
</div>

You can try ngx-pagination for pagination in Angular 2+.

Related

Access delete method body send via axios.delete

I am building a react-django simple blog app and I am trying to delete blog post but I also want to send body with delete to backend But I have no idea, How can I access delete body ?. I can do with post like self.request.POST with how with delete ?
App.js:
class BlogPost extends React.Component {
deleteBlog = (blog_title) => {
const body = ({title: blog_title});
const headers = {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json",
}
axios.delete("delete_blog/", blog_title, {headers:headers}).then(res => {console.log})
}
render() {
return (
<div>
{
this.state.blogs.map(res => <div>
{res.blog_title}
<button onClick={() => deleteBlog(res.blog_title)}></button>
</div>
}
</div>
)}}
views.py:
class BlogPost(APIView):
def post(self, *args, **kwargs):
.......
def delete(self, *args, **kwargs):
# Trying to access delete body here......
print(self.request.POST)
# It printed empty dict like <[QueryDict = {}]>
I have tried many times but it is still not showing.
To Use Axios Delete request with body , you need to use axios.delete(url,{ headers: { "Authorization": "***" }, data: { } } );
eg:
axios.delete("delete_blog/", {
headers: headers,
data: {
source: blog_title
}
});

Conection Angular 10 + Django Api Rest no render objetcs

im trying use Django rest + angular 10, i will show a list of providers in the browser, could someone explain to me why my django api rest objects are not rendering? appear in console but not in html.
im using angular 10, django 2.7, cors, and my localhost.
this is my code.
// app-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
const routes: Routes = [];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
//app.component.html
<div *ngFor='let provider of providers'>
<h2>{{ provider.name | uppercase }}</h2>
<p>{{ provider.procedence }}</p>
<p>{{ provider.email }}</p>
<p>{{ provider.telephone }}</p>
</div>
// app.component.ts
import { Component, OnInit } from '#angular/core';
import { ProviderService } from './provider.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'conexion';
providers: any[] = [];
constructor(
protected ProviderService: ProviderService
) {
}
ngOnInit() {
this.ProviderService.getProviders()
.subscribe(
(data) => { // Success
this.providers = data['results'];
console.warn(data)
},
(error) => {
console.error(error);
}
);
}
}
// app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpClientModule} from '#angular/common/http';
import { ProviderService } from './provider.service';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [ProviderService],
bootstrap: [AppComponent]
})
export class AppModule { }
// provider.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ProviderService {
constructor(protected http: HttpClient) { }
getProviders() {
return this.http.get('http://127.0.0.1:8000/provider?format=json');
}
}
To debug Use Async and learn how to use it, it's less code and less mistakes. Smart/Dumb components and OnPush Change Detection
Define
public providers$: Observable<any>;
ngOnInit
this.providers$ = this.ProviderService.getProviders();
Template
{{ providers$ | async | json }}

Uncaught TypeError: Super expression must either be null or a function [duplicate]

This question already has answers here:
Reactjs, Super expression must either be null or a function
(2 answers)
Closed 5 years ago.
So I'm new to React and even though I've found multiple others having the same issue, I still haven't found the error in my code. Therefore I turn to you stackoverflow, you're my only hope!
I am learning, so I wanted to create a simple ReactJS application that handles a HTTP-request. After finishing the code I encountered the error:
Uncaught TypeError: Super expression must either be null or a function, not object
at exports.default (inherits.js?0578:21)
at eval (app.js?71f7:22)
The error persists even though I've tried a lot of different changes and I am fairly certain that it's related to imports/exports as this is what a lot of other sources tell me, although double-checking imports etc. hasn't yielded any results.
The code:
app.js ( handles the rendering of a simple button and should execute a simple GET request on click )
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { createServerSagaRequest } from '../saga/serverSaga'
import { incrRequestAmount, requestSelector } from '../reducer/requestReducer'
const mapStateToProps = (state) => {
return {
getRequestAmount: requestSelector.requests(state),
}
}
const mapDispatchToProps = (dispatch) => {
return {
open: (url, data, action, method) => dispatch(createServerSagaRequest((url, data, action, method))),
requests: () => dispatch(incrRequestAmount()),
}
}
class App extends React {
constructor(props){
super(props)
}
_buttonClick() {
this.props.requests()
this.props.open("http://mvctestproject.local/GetData", "TestDataFraGet", action, "GET")
}
render(){
return (
<button
className="btn btn-default"
onClick={this._buttonClick()}>{this.props.getRequestAmount()}
</button>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
serverSaga.js (my saga which can access the reducer and service)
import React, { Component } from 'react'
import { put, call, take, fork, select } from 'redux-saga/effects'
import { callServer } from '../service/serverService'
import { incrRequestAmount, requestSelector } from '../reducer/requestReducer'
export function createServerSagaRequest() {return { type: CREATE_REQUEST }}
function* handleRequest(url, data, action, method, success){
incrRequestAmount()
return yield executeRequest(url, data, action, method, success)
}
function* executeRequest(url, data, action, method, success) {
let response = yield call(callServer, url, method, data)
let responseSuccess = response && response.Succeeded
return
}
export default function* serverSaga(){
yield [
fork(function*(){
yield call (CREATE_REQUEST, handleRequest)
}),
]
}
rootSaga.js ( grouping sagas - in case I made more )
import { fork } from 'redux-saga/effects'
import serverSaga from './serverSaga'
export default function* rootSaga(){
yield [
fork(serverSaga)
]
}
requestReducer.js ( only function is to increment a variable after each request)
import { fromJS } from 'immutable'
export function incrRequestAmount() {return {type: 'INCR_REQUESTS'}}
const initialState = {
requestAmount: 0
}
function requestReducer(state = fromJS(initialState), action){
switch(action.type){
case 'INCR_REQUESTS':
return state.updateIn(["requestAmount"], (requests) => requests++)
default:
return state
}
}
export const requestSelector = {
amount: state => state.requests.get('requestAmount')
}
export default requestReducer
reducers.js ( grouping reducers - in case i made more )
import { combineReducers } from 'redux'
import React, { Component } from 'react'
import requests from './requestReducer'
export default combineReducers({
requests,
})
serverService.js ( handles calls to the server (GET/POST)
import React, { Component } from 'react'
export function callServer(url, bodyData, method){
let methodType = method.toLowerCase()
return new Promise((resolve, reject) => {
let r;
switch (methodType){
case 'post':
r = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(bodyData)
}
break;
case 'get':
r = {
method: 'GET'
}
break;
}
if (r) {
console.log("URL: ", url)
fetch(url, r)
.then((response) => {
console.log("Resp: ", url, response)
return response.json()
})
}
})
}
You need to extend React.Component to create a component, not React itself:
class App extends React {
should be
class App extends React.Component {
, or since you imported Component directly
class App extends Component {

paypalrestsdk with Django integration issue

I am trying to setup Paypal express checkout with REST API but when I click checkout with Paypal I get modal window and it just spins forever.
Payment create view:
def payment_create(request):
logging.basicConfig(level=logging.INFO)
paypalrestsdk.configure({
'mode': settings.PAYPAL_MODE,
'client_id': settings.PAYPAL_CLIENT_ID,
'client_secret': settings.PAYPAL_CLIENT_SECRET
})
# Create payment object
payment = paypalrestsdk.Payment({
"intent": "sale",
# Set payment method
"payer": {
"payment_method": "paypal"},
# Set redirect urls
"redirect_urls": {
"return_url": "http://127.0.0.1:8000/checkout/payment_done/",
"cancel_url": "http://127.0.0.1:8000/checkout/payment_error/"},
# Set transaction object
"transactions": [{
"amount": {
"total": "10.00",
"currency": "USD"},
"description": "payment description"}]})
# Create Payment and return status
if payment.create():
print("Payment[%s] created successfully" % (payment.id))
request.session["paymentID"] = payment.id
# Redirect the user to given approval url
for link in payment.links:
if link.method == "REDIRECT":
print("Redirect for approval: %s" % (link.href))
return HttpResponseRedirect(link.href)
else:
print("Error while creating payment:")
print(payment.error)
Cart.html template:
<div id="paypal-button"></div>
<script src="https://www.paypalobjects.com/api/checkout.js" data-version-4></script>
<script>
paypal.Button.render({
env: 'sandbox', // Optional: specify 'sandbox' environment
payment: function(resolve, reject) {
var CREATE_PAYMENT_URL = 'http://127.0.0.1:8000/checkout/payment_create/';
paypal.request.post(CREATE_PAYMENT_URL)
.then(function(data) { resolve(data.paymentID); })
.catch(function(err) { reject(err); });
},
onAuthorize: function(data) {
// Note: you can display a confirmation page before executing
var EXECUTE_PAYMENT_URL = 'http://127.0.0.1:8000/checkout/payment_execute/';
paypal.request.post(EXECUTE_PAYMENT_URL,
{ paymentID: data.paymentID, payerID: data.payerID })
.then(function(data) { window.location.replace("http://127.0.0.1:8000/checkout/payment_done/") })
.catch(function(err) { window.location.replace("http://127.0.0.1:8000/checkout/payment_error/") });
}
}, '#paypal-button');
</script>
From logs looks like I am successfully creating payment object, but failing to redirect, in dev tools i am seeing this:
VM6073:1 Uncaught SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse ()
at XMLHttpRequest. (https://www.paypalobjects.com/api/checkout.js:10511:38)
After researching online seems like json is expected but i am returning html? Can anyone point me in the right direction.
I am new to programming so any help is appreciated!

Use value from select2:opening call as input to ajax autocomplete data parameter

I'm generating a table of results dynamically and one cell in each row contains an autocomplete. I'm using Select2 to display the autocomplete options and am populating the drop-down from ajax data and custom data unique for each row. My ajax data is coming from my Python app method and I'm using POST to send a variable back to the Python method to use to generate the custom data. Here's how this is set-up:
$(".js-example-tokenizer-ajax-data").select2({
tags: true,
createTag: function (params) {
return {
id: params.term,
text: params.term,
newOption: true
}
},
templateResult: function (data) {
var $result = $("<span></span>");
$result.text(data.text);
if (data.newOption) {
$result.append(" <em>(new)</em>");
}
return $result;
},
placeholder: 'Select an option',
maximumSelectionLength: 3,
ajax: {
url: '{{ url_for("select2Autocomplete") }}',
contentType: 'application/json',
method: "POST",
dataType : 'json',
data: JSON.stringify({variable:myValue}),
processResults: function (data) {
return {
results: data.resource_list
};
}
}
});
I've set the id of the select element to a value from my Jinja template.
<select onfocus="this.selectedIndex = -1;" id="{{ key }}" class="js-example-tokenizer-ajax-data" multiple="multiple" miriamId="{{ value }}" style="width:100%">
<option value="{{ key }}" selected>{{ miriam_name_dict[value] }}</option>
</select>
Since it's dynamic I don't know what that id is for each select. I am able to get the value like this:
$('.js-example-tokenizer-ajax-data').on('select2:opening', function (evt) {
myValue = document.getElementById(this.id).getAttribute('id');
console.log("myValue: ", myValue)
});
I'd like to use myValue as the variable I send back to my python method via the data variable. Is there some way to access myValue to use in the autocomplete code?
I was able to pass back data to the autocomplete method for the select element the user clicked on as follows:
$(".js-example-tokenizer-ajax-data").select2({
tags: true, //Allows for free text input of tag values
createTag: function (params) {
return {
id: params.term,
text: params.term,
newOption: true
}
},
templateResult: function (data) {
var $result = $("<span></span>");
$result.text(data.text);
if (data.newOption) {
$result.append(" <em>(new)</em>");
}
return $result;
},
placeholder: 'Select an option',
maximumSelectionLength: 3,
ajax: {
url: '{{ url_for("select2Autocomplete") }}',
contentType: 'application/json',
method: "POST",
dataType : 'json',
data: function() {
var myValue = $(this).attr('id');
return JSON.stringify({variable: myValue})
},
processResults: function (data) {
return {
results: data.resource_list
};
}
}
});
I was not able to use {variable: $(this).attr('id')} directly as the value for the data parameter and did need to use JSON.stringify on the value to get the value in the python method using jsonData = request.json["variable"]

Categories

Resources