Hello.
I got code which on shows me on page slider and other blocks. I have got a own API service which is load slider dynamicaly from my server and shows it. Slides (I have two) are shows after load. But the loop swipe of slide shows that swipe positions is only on first. And I can’t swipe it with loop option in true. The paraments for block I pass from attribute [config_private], and when apply it to code of slider.
My HttpQueryApi service use a buffer for queries. I need it because I will collect from many blocks on page component query for getting data to all of them at once. And after I’ll get the answer from my server, I’ll will use the callback methods in my blocks components to show the result.
Pay attention on it.
What’s can be the problem?
Working simple code below.
Here is page component and template
/**
* Controller of main page
*/
import { Component, AfterViewInit } from '@angular/core';
import { BannersSlideShow } from "../blocks/banners/slideshow";
import { HttpQueryService } from "../modelservices/http/httpqueryservice";
@Component({
templateUrl : 'build/templates/default/pages/main.html',
directives: [
BannersSlideShow
],
viewProviders: [
HttpQueryService //API wrapper to HTTP query and getting result (for few components at once)
]
})
export class MainPage implements AfterViewInit{
blocksData: any; //Blocks data
constructor(
private httpQueryService: HttpQueryService
)
{
}
ngAfterViewInit()
{
console.log('Main page', 2);
this.httpQueryService.sendQueriesPartially(); //Sending multi query to get data for blocks
}
}
and it’s template is:
<ion-content>
<blocks-banners-slideshow #block class="contentBlock" [config]="{zone: 'main'}" [config_private]="{url: 'http://test22.local/mobilesiteapp/getsliderbanners/'}" [slideOptions]="{loop: true}"></blocks-banners-slideshow>
<!--<blocks-catalog-category #block class="contentBlock" [config]="{root: 0}"></blocks-catalog-category>
<blocks-catalog-topproducts #block class="contentBlock" [config]="{dirs: [0]}"></blocks-catalog-topproducts>-->
</ion-content>
Here is a block component code:
/**
* Banners slider component
*/
import {Component, Input, OnInit} from '@angular/core';
import { BannersService } from "../../modelservices/catalog/bannersservice";
import { BannerItem } from "../../modelservices/catalog/items/banner";
import { HttpQueryService } from "../../modelservices/http/httpqueryservice";
import { ToastController } from "ionic-angular";
@Component({
selector: 'blocks-banners-slideshow', //Selector
templateUrl: 'build/templates/default/blocks/banners/slideshow.html', //template
styleUrls: [ //Own styles
'resource/default/css/banners/slideshow.css'
],
providers: [
BannersService
] //Needed APIs
})
export class BannersSlideShow implements OnInit{
list: Array<BannerItem>;
mySlideOptions: any;
//My input data
@Input() config: any;
@Input() config_private: any;
@Input() slideOptions = {};
/**
* Конструктор класса
* @param bannersService - API for banners
* @param httpQueryService - API queries to site for blocks
* @param toastCtrl - contorller for modifications
*/
constructor(
private bannersService: BannersService,
private httpQueryService: HttpQueryService, //Wrapper for HTTP query
public toastCtrl: ToastController
){
}
ngOnInit()
{
this.list = [];
this.mySlideOptions = this.slideOptions;//setting options of slider
//adding block query to buffer
this.httpQueryService.addQueryToBuffer(this.config_private['url'], this.config, this);
}
/**
* Append block with banners
* @param data - data with banners from server
*/
getItems(data: Object)
{
if (data.hasOwnProperty('list') && data['list'].length){ //If banners are present
for(var i=0; i<data['list'].length; i++){
this.bannersService.add(data['list'][i]);
}
this.list = this.bannersService.getList();
}else{
this.showToast('No banners for zone "'+this.config['zone']+'"', 'bottom');
}
}
/**
* Shows toast notification
* @param message - message
* @param position - position (top|bottom|middle)
*/
showToast(message: string, position: string):void
{
let toast = this.toastCtrl.create({
message: message,
duration: 3000,
position: position
});
toast.present();
}
}
And it’s template:
<ion-slides *ngIf="list" class="slideShowWrapper" [options]="mySlideOptions">
<ion-slide *ngFor="let item of list">
<img [src]="item.url" alt="{{item.title}}"/>
</ion-slide>
</ion-slides>
BannerItem:
export class BannerItem{
title: string; //name of banner
url: string; //Link to image
}
BannersService:
import { BannerItem } from "./items/banner";
import { Injectable } from "@angular/core";
/**
* API for banners
*/
@Injectable()
export class BannersService{
list = [];
/**
* Return banners array
*
*/
getList(): Array<BannerItem>
{
return this.list;
}
/**
* Adding a banner
*
* @param data - Array of parameters for banner
*/
add(data: any): void
{
var banner = new BannerItem();
Object.keys(data).forEach(function(key){ //Loop the object to fill BannerItem class
banner[key] = data[key];
});
this.list.push(data);
}
}
HttpServiceAPI
import { Injectable } from “@angular/core”;
import { Response, Http } from “@angular/http”;
import ‘rxjs/add/operator/toPromise’;
/**
* API for queries to site
*/
@Injectable()
export class HttpQueryService
{
queryCache = []; //Cache of queries
queryBuffer = []; //Buffer for queries
constructor(
private http: Http
){
}
/**
* Adding query to buffer
* @param url - server address
* @param params - additional params
* @param callbackBlock - block for callback method call
*/
addQueryToBuffer(url:string, params: Object, callbackBlock):void
{
this.queryBuffer.push({ //Adding to buffers our query
url: url,
params: params,
callbackBlock: callbackBlock //Block form callback in future
});
}
/**
* Clear the query buffer
*/
clearQueryBuffer():void
{
this.queryBuffer = [];
}
/**
* Send the queries to server from query buffer array
*/
sendQueriesPartially():void
{
if (!this.queryBuffer.length){ //Если запрсов нет
return;
}
for(var i=0; i<this.queryBuffer.length; i++){
var url = this.queryBuffer[i]['url']+this.objectToParametersString(this.queryBuffer[i]['params']); //Url for query
console.log('Try to query data from '+url);
if (!this.isInQueryCache(url)){
var $this = this;
(function ($this){ //Making closure for callback block return
var callbackBlock = $this.queryBuffer[i]['callbackBlock']; //Функция для отработки
$this.http.get(url)
.toPromise()
.then(result => { //Если всё успешно получим результат и запишем в кэш
$this.success(result, callbackBlock);
})
.catch($this.handleError); //Если есть ошибки, то обработаем
})($this);
}
}
this.clearQueryBuffer(); //Clear the buffers
}
/**
* Is success try to call method from component
* @param result - объект резульатата запроса
* @param callback - блок для возврата
* @returns {any|{}}
*/
private success(result: Response, callbackBlock):void
{
let res = this.extractData(result);
this.setQueryCache(result.url, res); //Установимм кэш
callbackBlock.getItems(res);
}
/**
* Convert object to params string
* return the query part string
* @param obj - объект ключ - значение
* @returns {string}
*/
private objectToParametersString(obj: Object):string
{
let result = Object.keys(obj).reduce((prev, key, i) => (
`${prev}${i!=0?'&':''}${key}=${obj[key]}`
), '');
return result.length ? "?" + result : "";
}
/**
* Return data in right way
* @param res - объект результата запроса
* @returns {any|Uint8ClampedArray|string|ArrayBuffer|{}}
*/
private extractData(res: Response)
{
let body = res.json();
return body || { };
}
/**
* Shows the queries error
* @param error
* @returns {Promise<void>|Promise<T>}
*/
private handleError (error: any)
{
//If we have error
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error('http query Error = ', errMsg); // log to console instead
return Promise.reject(errMsg);
}
/**
* Set the value to cache
* @param key - key
* @param value - value
*/
private setQueryCache(key: string, value: Object):void
{
this.queryCache[key] = value;
}
/**
* return the value from cache
*
* @param key - key
* @returns {any}
*/
private getQueryCache(key: string):any
{
return this.queryCache[key] ? this.queryCache[key] : false;
}
/**
* Checks the value in cache
* @param key - key
* @returns {boolean}
*/
private isInQueryCache(key: string):boolean
{
return this.queryCache[key] ? true : false;
}
}
And at last PHP side of my server. Code is good for me for my framework (actionGetSliderBanners):
<?php
namespace MobileSiteApp\Controller\Front;
/**
* App controller
*/
class Gate extends \RS\Controller\Front
{
public
$api,
$config;
function init()
{
$this->api = new \Catalog\Model\Api();
$this->config = \RS\Config\Loader::byModule($this);
}
/**
* Set headers to answer for cross-domain queries
*
*/
function setOutPutHeaders()
{
$this->app->headers->addHeader('Access-Control-Allow-Credentials', 'true');
$this->app->headers->addHeader('Access-Control-Allow-Origin', '*');
$this->app->headers->addHeader('Access-Control-Allow-Methods', 'GET, POST');
$this->app->headers->addHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
$this->app->headers->addHeader('Content-type', 'application/json');
}
function actionIndex()
{
}
/**
* Returns the banners in json for Ionic 2
*
*/
function actionGetSliderBanners()
{
$zone = $this->url->request('zone', TYPE_STRING, false);
$banners = array();
if ($zone){ //If the zone is present
$banners[] = array(
'title' => t('Banner 1'),
'url' => 'http://full.readyscript.ru/storage/banners/resized/axy_1000x653/be60cd89af5aa5b0cb3c1fa9a0932e3d_ddba8c9b.jpg'
);
$banners[] = array(
'title' => t('Banner 2'),
'url' => 'http://full.readyscript.ru/storage/banners/resized/axy_1000x653/d6c7d6de8bb0ad2f791c080232be2047_5bdc0bdd.jpg'
);
}
$this->setOutPutHeaders(); //Add headers
$this->wrapOutput(false);
return json_encode(array('success' => true, 'list' => $banners));
}
}