diff --git a/src/app/search-multiple/containers/result.component.html b/src/app/search-multiple/containers/result.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..95c32c87c658a06e90d72124970e962bdf7fed3c
--- /dev/null
+++ b/src/app/search-multiple/containers/result.component.html
@@ -0,0 +1,61 @@
+<div *ngIf="(datasetSearchMetaIsLoading | async) || (attributeSearchMetaIsLoading | async)"
+    class="row justify-content-center mt-5">
+    <span class="fas fa-circle-notch fa-spin fa-3x"></span>
+    <span class="sr-only">Loading...</span>
+</div>
+<div *ngIf="(datasetSearchMetaIsLoaded | async) && (attributeSearchMetaIsLoaded | async)" class="row mt-4">
+    <div class="col-12">
+        <app-result-download
+            [datasetName]="datasetName | async"
+            [datasetList]="datasetList | async"
+            [dataLength]="dataLength | async"
+            [isConeSearchAdded]="isConeSearchAdded | async"
+            [coneSearch]="coneSearch | async"
+            [criteriaList]="criteriaList | async"
+            [outputList]="outputList | async">
+        </app-result-download>
+        <app-reminder
+            [datasetAttributeList]="datasetAttributeList | async"
+            [isConeSearchAdded]="isConeSearchAdded | async"
+            [coneSearch]="coneSearch | async"
+            [criteriaFamilyList]="criteriaFamilyList | async"
+            [criteriaList]="criteriaList | async"
+            [outputFamilyList]="outputFamilyList | async"
+            [categoryList]="categoryList | async"
+            [outputList]="outputList | async">
+        </app-reminder>
+        <app-result-url-display
+            [datasetList]="datasetList | async"
+            [datasetName]="datasetName | async"
+            [isConeSearchAdded]="isConeSearchAdded | async"
+            [coneSearch]="coneSearch | async"
+            [criteriaList]="criteriaList | async"
+            [outputList]="outputList | async">
+        </app-result-url-display>
+        <app-result-datatable
+            [datasetName]="datasetName | async"
+            [datasetList]="datasetList | async"
+            [queryParams]="queryParams | async"
+            [datasetAttributeList]="datasetAttributeList | async"
+            [outputList]="outputList | async"
+            [searchData]="searchData | async"
+            [dataLength]="dataLength | async"
+            [selectedData]="selectedData | async"
+            (getSearchData)="getSearchData($event)"
+            (addSelectedData)="addSearchData($event)"
+            (deleteSelectedData)="deleteSearchData($event)"
+            [processWip]="processWip | async"
+            [processDone]="processDone | async"
+            [processId]="processId | async"
+            (executeProcess)="executeProcess($event)">
+        </app-result-datatable>
+    </div>
+</div>
+<div class="row mt-5 justify-content-between">
+    <div class="col">
+        <a routerLink="/search/output/{{ datasetName | async }}" [queryParams]="queryParams | async"
+            class="btn btn-outline-secondary">
+            <span class="fas fa-arrow-left"></span> Previous
+        </a>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/search-multiple/containers/result.component.spec.ts b/src/app/search-multiple/containers/result.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dc458148cdbefe510476ffe411ba567c6c0926e3
--- /dev/null
+++ b/src/app/search-multiple/containers/result.component.spec.ts
@@ -0,0 +1,161 @@
+import { ComponentFixture, TestBed, async } from '@angular/core/testing';
+import { provideMockStore, MockStore } from '@ngrx/store/testing';
+import { Component, Input } from '@angular/core';
+
+import { ResultComponent } from './result.component';
+import * as fromMetamodel from '../../metamodel/reducers';
+import * as fromSearch from '../store/search.reducer';
+import * as fromConeSearch from '../../shared/cone-search/store/cone-search.reducer';
+import * as datasetActions from '../../metamodel/action/dataset.action';
+import * as searchActions from '../store/search.action';
+import { Dataset, Attribute, Family, Category } from 'src/app/metamodel/model';
+import { Criterion, SearchQueryParams } from '../store/model';
+import { ScrollTopService } from '../../shared/service/sroll-top.service';
+import { RouterLinkDirectiveStub } from '../../../settings/test-data/router-link-directive-stub';
+import { ConeSearch } from "../../shared/cone-search/store/model";
+
+describe('[Search] Container: ResultComponent', () => {
+    @Component({ selector: 'app-result-download', template: '' })
+    class DownloadSectionStubComponent {
+        @Input() datasetName: string;
+        @Input() datasetList: Dataset[];
+        @Input() dataLength: number;
+        @Input() isConeSearchAdded: boolean;
+        @Input() coneSearch: ConeSearch;
+        @Input() criteriaList: Criterion[];
+        @Input() outputList: number[];
+    }
+
+    @Component({ selector: 'app-reminder', template: '' })
+    class ReminderStubComponent {
+        @Input() datasetAttributeList: Attribute[];
+        @Input() isConeSearchAdded: boolean;
+        @Input() coneSearch: ConeSearch;
+        @Input() criteriaList: Criterion[];
+        @Input() criteriaFamilyList: Family[];
+        @Input() outputFamilyList: Family[];
+        @Input() categoryList: Category[];
+        @Input() outputList: number[];
+    }
+
+    @Component({ selector: 'app-result-url-display', template: '' })
+    class UrlDisplaySectionStubComponent {
+        @Input() datasetList: Dataset[];
+        @Input() datasetName: string;
+        @Input() isConeSearchAdded: boolean;
+        @Input() coneSearch: ConeSearch;
+        @Input() criteriaList: Criterion[];
+        @Input() outputList: number[];
+    }
+
+    @Component({ selector: 'app-result-datatable', template: '' })
+    class DatatableSectionStubComponent {
+        @Input() datasetName: string;
+        @Input() datasetList: Dataset[];
+        @Input() queryParams: SearchQueryParams;
+        @Input() datasetAttributeList: Attribute[];
+        @Input() outputList: number[];
+        @Input() searchData: any[];
+        @Input() dataLength: number;
+        @Input() selectedData: any[];
+        @Input() processWip: boolean;
+        @Input() processDone: boolean;
+        @Input() processId: string;
+    }
+
+    let scrollTopServiceStub: Partial<ScrollTopService> = {
+        setScrollTop() {}
+    };
+
+    let component: ResultComponent;
+    let fixture: ComponentFixture<ResultComponent>;
+    let store: MockStore;
+    const initialState = {
+        search: { ...fromSearch.initialState },
+        metamodel: { ...fromMetamodel },
+        coneSearch: { ...fromConeSearch }
+    };
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                ResultComponent,
+                DownloadSectionStubComponent,
+                ReminderStubComponent,
+                UrlDisplaySectionStubComponent,
+                DatatableSectionStubComponent,
+                RouterLinkDirectiveStub
+            ],
+            providers: [
+                provideMockStore({ initialState }),
+                { provide: ScrollTopService, useValue: scrollTopServiceStub }
+            ]
+        });
+        fixture = TestBed.createComponent(ResultComponent);
+        component = fixture.componentInstance;
+        store = TestBed.inject(MockStore);
+    }));
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should execute ngOnInit lifecycle', (done) => {
+        const loadDatasetSearchMetaAction = new datasetActions.LoadDatasetSearchMetaAction();
+        const changeStepAction = new searchActions.ChangeStepAction('result');
+        const resultChecked = new searchActions.ResultChecked();
+        const initSearchByUrl = new searchActions.InitSearchByUrl();
+        const spy = spyOn(store, 'dispatch');
+        component.ngOnInit();
+        Promise.resolve(null).then(function() {
+            expect(spy).toHaveBeenCalledTimes(4);
+            expect(spy).toHaveBeenCalledWith(loadDatasetSearchMetaAction);
+            expect(spy).toHaveBeenCalledWith(changeStepAction);
+            expect(spy).toHaveBeenCalledWith(resultChecked);
+            expect(spy).toHaveBeenCalledWith(initSearchByUrl);
+            done();
+        });
+    });
+
+    it('#getSearchData() should dispatch RetrieveDataAction and GetDataLengthAction', () => {
+        const retrieveDataAction = new searchActions.RetrieveDataAction([1, 2, 3, 'four']);
+        const getDataLengthAction = new searchActions.GetDataLengthAction();
+        const spy = spyOn(store, 'dispatch');
+        component.getSearchData([1, 2, 3, 'four']);
+        expect(spy).toHaveBeenCalledTimes(2);
+        expect(spy).toHaveBeenCalledWith(retrieveDataAction);
+        expect(spy).toHaveBeenCalledWith(getDataLengthAction);
+    });
+
+    it('#addSearchData() should dispatch AddSelectedDataAction', () => {
+        const addSelectedDataAction = new searchActions.AddSelectedDataAction('toto');
+        const spy = spyOn(store, 'dispatch');
+        component.addSearchData('toto');
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(addSelectedDataAction);
+    });
+
+    it('#deleteSearchData() should dispatch DeleteSelectedDataAction', () => {
+        const deleteSelectedDataAction = new searchActions.DeleteSelectedDataAction('toto');
+        const spy = spyOn(store, 'dispatch');
+        component.deleteSearchData('toto');
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(deleteSelectedDataAction);
+    });
+
+    it('#executeProcess() should dispatch ExecuteProcessAction', () => {
+        const executeProcessAction = new searchActions.ExecuteProcessAction('toto');
+        const spy = spyOn(store, 'dispatch');
+        component.executeProcess('toto');
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(executeProcessAction);
+    });
+
+    it('#ngOnDestroy() should dispatch DestroyResultsAction', () => {
+        const destroyResultsAction = new searchActions.DestroyResultsAction();
+        const spy = spyOn(store, 'dispatch');
+        component.ngOnDestroy();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(destroyResultsAction);
+    });
+});
diff --git a/src/app/search-multiple/containers/result.component.ts b/src/app/search-multiple/containers/result.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..385811068eb368fba81c3e0c33f3b3475c51154d
--- /dev/null
+++ b/src/app/search-multiple/containers/result.component.ts
@@ -0,0 +1,43 @@
+import { Component, OnInit, OnDestroy } from '@angular/core';
+
+import { Observable } from 'rxjs';
+import { Store } from '@ngrx/store';
+
+import { Criterion, SearchQueryParams } from '../store/model';
+import { Dataset, Attribute, Family, Category } from '../../metamodel/model';
+import { ConeSearch } from "../../shared/cone-search/store/model";
+import * as searchActions from '../store/search.action';
+import * as datasetActions from '../../metamodel/action/dataset.action';
+import * as fromSearch from '../store/search.reducer';
+import * as fromMetamodel from '../../metamodel/reducers';
+import * as searchSelector from '../store/search.selector';
+import * as metamodelSelector from '../../metamodel/selectors';
+import * as coneSearchSelector from '../../shared/cone-search/store/cone-search.selector';
+import { ScrollTopService } from '../../shared/service/sroll-top.service';
+
+interface StoreState {
+    searchMultiple: fromSearchMultiple.State;
+    metamodel: fromMetamodel.State;
+}
+
+@Component({
+    selector: 'app-result-multiple',
+    templateUrl: 'result.component.html'
+})
+export class ResultMultipleComponent implements OnInit {
+    // public datasetSearchMetaIsLoading: Observable<boolean>;
+
+    constructor(private store: Store<StoreState>, private scrollTopService: ScrollTopService) {
+        // this.datasetSearchMetaIsLoading = store.select(metamodelSelector.getDatasetSearchMetaIsLoading);
+    }
+
+    ngOnInit() {
+        // Create a micro task that is processed after the current synchronous code
+        // This micro task prevent the expression has changed after view init error
+        // Promise.resolve(null).then(() => this.store.dispatch(new searchActions.ChangeStepAction('result')));
+        // Promise.resolve(null).then(() => this.store.dispatch(new searchActions.ResultChecked()));
+        // Promise.resolve(null).then(() => this.store.dispatch(new searchActions.InitSearchByUrl()));
+        // this.store.dispatch(new datasetActions.LoadDatasetSearchMetaAction());
+        this.scrollTopService.setScrollTop();
+    }
+}
diff --git a/src/app/search-multiple/search-multiple-routing.module.ts b/src/app/search-multiple/search-multiple-routing.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..949d486f317bf1a2c09efe245434d1dc3e55d9a2
--- /dev/null
+++ b/src/app/search-multiple/search-multiple-routing.module.ts
@@ -0,0 +1,31 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { SearchMultipleComponent } from './containers/search.component';
+import { ResultMultipleComponent } from './containers/result.component';
+
+const routes: Routes = [
+    {
+        path: '', component: SearchComponent, children: [
+            { path: '', redirectTo: 'dataset', pathMatch: 'full' },
+            { path: 'dataset', component: DatasetComponent },
+            { path: 'criteria/:dname', component: CriteriaComponent },
+            { path: 'output/:dname', component: OutputComponent },
+            { path: 'result/:dname', component: ResultComponent }
+        ]
+    }
+];
+
+@NgModule({
+    imports: [RouterModule.forChild(routes)],
+    exports: [RouterModule]
+})
+export class SearchMultipleRoutingModule { }
+
+export const routedComponents = [
+    SearchComponent,
+    DatasetComponent,
+    CriteriaComponent,
+    OutputComponent,
+    ResultComponent
+];
diff --git a/src/app/search-multiple/search-multiple.module.ts b/src/app/search-multiple/search-multiple.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..19006919b6e658cda420f46ecbb3b32f170b5737
--- /dev/null
+++ b/src/app/search-multiple/search-multiple.module.ts
@@ -0,0 +1,28 @@
+import { NgModule } from '@angular/core';
+
+import { StoreModule } from '@ngrx/store';
+import { EffectsModule } from '@ngrx/effects';
+
+import { SharedModule } from '../shared/shared.module';
+import { MetamodelModule } from '../metamodel/metamodel.module';
+import { SearchMultipleEffects } from './store/search-multiple.effects';
+import { SearchMultipleService } from './store/search-multiple.service';
+import { SearchMultipleRoutingModule, routedComponents } from './search-multiple-routing.module';
+import { dummiesComponents } from './components';
+import { reducer } from './store/search-multiple.reducer';
+
+@NgModule({
+    imports: [
+        SharedModule,
+        MetamodelModule,
+        SearchMultipleRoutingModule,
+        StoreModule.forFeature('search-multiple', reducer),
+        EffectsModule.forFeature([SearchMultipleEffects])
+    ],
+    declarations: [
+        routedComponents,
+        dummiesComponents
+    ],
+    providers: [SearchMultipleService]
+})
+export class SearchMultipleModule { }
diff --git a/src/app/search-multiple/store/search-multiple.action.spec.ts b/src/app/search-multiple/store/search-multiple.action.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fbee347b2e3a23518e22c1ab880d411754ded196
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.action.spec.ts
@@ -0,0 +1,154 @@
+import * as searchActions from '../store/search.action';
+import { Criterion } from './model';
+import { CRITERIA_LIST } from 'src/settings/test-data';
+
+describe('[Search] Action', () => {
+    it('should create InitSearchByUrl action', () => {
+        const action = new searchActions.InitSearchByUrl();
+        expect(action.type).toEqual(searchActions.INIT_SEARCH_BY_URL);
+    });
+
+    it('should create ChangeStepAction', () => {
+        const action = new searchActions.ChangeStepAction('toto');
+        expect(action.type).toEqual(searchActions.CHANGE_STEP);
+        expect(action.payload).toEqual('toto');
+    });
+
+    it('should create SelectDatasetAction', () => {
+        const action = new searchActions.SelectDatasetAction('toto');
+        expect(action.type).toEqual(searchActions.SELECT_DATASET);
+        expect(action.payload).toEqual('toto');
+    });
+
+    it('should create NewSearchAction', () => {
+        const action = new searchActions.NewSearchAction('toto');
+        expect(action.type).toEqual(searchActions.NEW_SEARCH);
+        expect(action.payload).toEqual('toto');
+    });
+
+    it('should create CriteriaChecked action', () => {
+        const action = new searchActions.CriteriaChecked();
+        expect(action.type).toEqual(searchActions.CRITERIA_CHECKED);
+    });
+
+    it('should create OutputChecked action', () => {
+        const action = new searchActions.OutputChecked();
+        expect(action.type).toEqual(searchActions.OUTPUT_CHECKED);
+    });
+
+    it('should create ResultChecked action', () => {
+        const action = new searchActions.ResultChecked();
+        expect(action.type).toEqual(searchActions.RESULT_CHECKED);
+    });
+
+    it('should create IsConeSearchAddedAction', () => {
+        const action = new searchActions.IsConeSearchAddedAction(true);
+        expect(action.type).toEqual(searchActions.IS_CONE_SEARCH_ADDED);
+        expect(action.payload).toBeTruthy();
+    });
+
+    it('should create UpdateCriteriaListAction', () => {
+        const criteriaList: Criterion[] = CRITERIA_LIST;
+        const action = new searchActions.UpdateCriteriaListAction(criteriaList);
+        expect(action.type).toEqual(searchActions.UPDATE_CRITERIA_LIST);
+        expect(action.payload).toEqual(criteriaList);
+    });
+
+    it('should create AddCriterionAction', () => {
+        const criterion: Criterion = CRITERIA_LIST[0];
+        const action = new searchActions.AddCriterionAction(criterion);
+        expect(action.type).toEqual(searchActions.ADD_CRITERION);
+        expect(action.payload).toEqual(criterion);
+    });
+
+    it('should create DeleteCriterionAction', () => {
+        const action = new searchActions.DeleteCriterionAction(1);
+        expect(action.type).toEqual(searchActions.DELETE_CRITERION);
+        expect(action.payload).toEqual(1);
+    });
+
+    it('should create UpdateOutputListAction', () => {
+        const action = new searchActions.UpdateOutputListAction([1, 2]);
+        expect(action.type).toEqual(searchActions.UPDATE_OUTPUT_LIST);
+        expect(action.payload).toEqual([1, 2]);
+    });
+
+    it('should create OutputListEmptyAction', () => {
+        const action = new searchActions.OutputListEmptyAction(true);
+        expect(action.type).toEqual(searchActions.OUTPUT_LIST_EMPTY);
+        expect(action.payload).toBeTruthy();
+    });
+
+    it('should create RetrieveDataAction', () => {
+        const action = new searchActions.RetrieveDataAction([1, 2, 3, 'four']);
+        expect(action.type).toEqual(searchActions.RETRIEVE_DATA);
+        expect(action.payload).toEqual([1, 2, 3, 'four']);
+    });
+
+    it('should create RetrieveDataSuccessAction', () => {
+        const action = new searchActions.RetrieveDataSuccessAction(['toto']);
+        expect(action.type).toEqual(searchActions.RETRIEVE_DATA_SUCCESS);
+        expect(action.payload).toEqual(['toto']);
+    });
+
+    it('should create RetrieveDataFailAction', () => {
+        const action = new searchActions.RetrieveDataFailAction();
+        expect(action.type).toEqual(searchActions.RETRIEVE_DATA_FAIL);
+    });
+
+    it('should create GetDataLengthAction', () => {
+        const action = new searchActions.GetDataLengthAction();
+        expect(action.type).toEqual(searchActions.GET_DATA_LENGTH);
+    });
+
+    it('should create GetDataLengthSuccessAction', () => {
+        const action = new searchActions.GetDataLengthSuccessAction(1);
+        expect(action.type).toEqual(searchActions.GET_DATA_LENGTH_SUCCESS);
+        expect(action.payload).toEqual(1);
+    });
+
+    it('should create GetDataLengthFailAction', () => {
+        const action = new searchActions.GetDataLengthFailAction();
+        expect(action.type).toEqual(searchActions.GET_DATA_LENGTH_FAIL);
+    });
+
+    it('should create AddSelectedDataAction', () => {
+        const action = new searchActions.AddSelectedDataAction(1);
+        expect(action.type).toEqual(searchActions.ADD_SELECTED_DATA);
+        expect(action.payload).toEqual(1);
+    });
+
+    it('should create DeleteSelectedDataAction', () => {
+        const action = new searchActions.DeleteSelectedDataAction(1);
+        expect(action.type).toEqual(searchActions.DELETE_SELECTED_DATA);
+        expect(action.payload).toEqual(1);
+    });
+
+    it('should create ExecuteProcessAction', () => {
+        const action = new searchActions.ExecuteProcessAction('toto');
+        expect(action.type).toEqual(searchActions.EXECUTE_PROCESS);
+        expect(action.payload).toEqual('toto');
+    });
+
+    it('should create ExecuteProcessWipAction', () => {
+        const action = new searchActions.ExecuteProcessWipAction('toto');
+        expect(action.type).toEqual(searchActions.EXECUTE_PROCESS_WIP);
+        expect(action.payload).toEqual('toto');
+    });
+
+    it('should create ExecuteProcessSuccessAction', () => {
+        const action = new searchActions.ExecuteProcessSuccessAction('toto');
+        expect(action.type).toEqual(searchActions.EXECUTE_PROCESS_SUCCESS);
+        expect(action.payload).toEqual('toto');
+    });
+
+    it('should create ExecuteProcessFailAction', () => {
+        const action = new searchActions.ExecuteProcessFailAction();
+        expect(action.type).toEqual(searchActions.EXECUTE_PROCESS_FAIL);
+    });
+
+    it('should create DestroyResultsAction', () => {
+        const action = new searchActions.DestroyResultsAction();
+        expect(action.type).toEqual(searchActions.DESTROY_RESULTS);
+    });
+});
diff --git a/src/app/search-multiple/store/search-multiple.action.ts b/src/app/search-multiple/store/search-multiple.action.ts
new file mode 100644
index 0000000000000000000000000000000000000000..179c52af6d87754748bc155a5f1f6d63393197cd
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.action.ts
@@ -0,0 +1,216 @@
+import { Action } from '@ngrx/store';
+
+import { Criterion } from './model';
+
+export const INIT_SEARCH_BY_URL = '[Search] Init Search By Url';
+export const CHANGE_STEP = '[Search] Change Search Step';
+export const SELECT_DATASET = '[Search] Select Dataset';
+export const NEW_SEARCH = '[Search] New Search';
+export const CRITERIA_CHECKED = '[Search] Criteria Checked';
+export const OUTPUT_CHECKED = '[Search] Output Checked';
+export const RESULT_CHECKED = '[Search] Result Checked';
+export const IS_CONE_SEARCH_ADDED = '[Search] Is Cone Search Added';
+export const UPDATE_CRITERIA_LIST = '[Search] Update Criteria List';
+export const ADD_CRITERION = '[Search] Add Criterion';
+export const DELETE_CRITERION = '[Search] Delete Criterion';
+export const UPDATE_OUTPUT_LIST = '[Search] Update Output List';
+export const OUTPUT_LIST_EMPTY = '[Search] Output List Empty';
+export const RETRIEVE_DATA = '[Search] Retrieve Data';
+export const RETRIEVE_DATA_SUCCESS = '[Search] Retrieve Data Success';
+export const RETRIEVE_DATA_FAIL = '[Search] Retrieve Data Fail';
+export const GET_DATA_LENGTH = '[Search] Get Data Length';
+export const GET_DATA_LENGTH_SUCCESS = '[Search] Get Data Length Success';
+export const GET_DATA_LENGTH_FAIL = '[Search] Get Data Length Fail';
+export const ADD_SELECTED_DATA = '[Search] Add Selected Data';
+export const DELETE_SELECTED_DATA = '[Search] Delete Selected Data';
+export const EXECUTE_PROCESS = '[Search] Execute Process';
+export const EXECUTE_PROCESS_WIP = '[Search] Execute Process WIP';
+export const EXECUTE_PROCESS_SUCCESS = '[Search] Execute Process Success';
+export const EXECUTE_PROCESS_FAIL = '[Search] Execute Process Fail';
+export const DESTROY_RESULTS = '[Search] Destroy Results';
+
+
+export class InitSearchByUrl implements Action {
+    readonly type = INIT_SEARCH_BY_URL;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class ChangeStepAction implements Action {
+    readonly type = CHANGE_STEP;
+
+    constructor(public payload: string) { }
+}
+
+export class SelectDatasetAction implements Action {
+    readonly type = SELECT_DATASET;
+
+    constructor(public payload: string) { }
+}
+
+export class NewSearchAction implements Action {
+    readonly type = NEW_SEARCH;
+
+    constructor(public payload: string) { }
+}
+
+export class CriteriaChecked implements Action {
+    readonly type = CRITERIA_CHECKED;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class OutputChecked implements Action {
+    readonly type = OUTPUT_CHECKED;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class ResultChecked implements Action {
+    readonly type = RESULT_CHECKED;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class IsConeSearchAddedAction implements Action {
+    readonly type = IS_CONE_SEARCH_ADDED;
+
+    constructor(public payload: boolean) { }
+}
+
+export class UpdateCriteriaListAction implements Action {
+    readonly type = UPDATE_CRITERIA_LIST;
+
+    constructor(public payload: Criterion[]) { }
+}
+
+export class AddCriterionAction implements Action {
+    readonly type = ADD_CRITERION;
+
+    constructor(public payload: Criterion) { }
+}
+
+export class DeleteCriterionAction implements Action {
+    readonly type = DELETE_CRITERION;
+
+    constructor(public payload: number) { }
+}
+
+export class UpdateOutputListAction implements Action {
+    readonly type = UPDATE_OUTPUT_LIST;
+
+    constructor(public payload: number[]) { }
+}
+
+export class RetrieveDataAction implements Action {
+    readonly type = RETRIEVE_DATA;
+
+    // [nbItems, page, sortedCol, sortedOrder]
+    constructor(public payload: [number, number, number, string]) { }
+}
+
+export class RetrieveDataSuccessAction implements Action {
+    readonly type = RETRIEVE_DATA_SUCCESS;
+
+    constructor(public payload: any[]) { }
+}
+
+export class RetrieveDataFailAction implements Action {
+    readonly type = RETRIEVE_DATA_FAIL;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class GetDataLengthAction implements Action {
+    readonly type = GET_DATA_LENGTH;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class GetDataLengthSuccessAction implements Action {
+    readonly type = GET_DATA_LENGTH_SUCCESS;
+
+    constructor(public payload: number) { }
+}
+
+export class GetDataLengthFailAction implements Action {
+    readonly type = GET_DATA_LENGTH_FAIL;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class AddSelectedDataAction implements Action {
+    readonly type = ADD_SELECTED_DATA;
+
+    constructor(public payload: number | string) { }
+}
+
+export class DeleteSelectedDataAction implements Action {
+    readonly type = DELETE_SELECTED_DATA;
+
+    constructor(public payload: number | string) { }
+}
+
+export class ExecuteProcessAction implements Action {
+    readonly type = EXECUTE_PROCESS;
+
+    constructor(public payload: string) { }
+}
+
+export class ExecuteProcessWipAction implements Action {
+    readonly type = EXECUTE_PROCESS_WIP;
+
+    constructor(public payload: string) { }
+}
+
+export class ExecuteProcessSuccessAction implements Action {
+    readonly type = EXECUTE_PROCESS_SUCCESS;
+
+    constructor(public payload: any) { }
+}
+
+export class ExecuteProcessFailAction implements Action {
+    readonly type = EXECUTE_PROCESS_FAIL;
+
+    constructor(public payload: {} = null) { }
+}
+
+export class OutputListEmptyAction implements Action {
+    readonly type = OUTPUT_LIST_EMPTY;
+
+    constructor(public payload: boolean) { }
+}
+
+export class DestroyResultsAction implements Action {
+    readonly type = DESTROY_RESULTS;
+
+    constructor(public payload: {} = null) { }
+}
+
+export type Actions
+    = InitSearchByUrl
+    | ChangeStepAction
+    | SelectDatasetAction
+    | NewSearchAction
+    | CriteriaChecked
+    | OutputChecked
+    | ResultChecked
+    | IsConeSearchAddedAction
+    | UpdateCriteriaListAction
+    | AddCriterionAction
+    | DeleteCriterionAction
+    | UpdateOutputListAction
+    | OutputListEmptyAction
+    | RetrieveDataAction
+    | RetrieveDataSuccessAction
+    | RetrieveDataFailAction
+    | GetDataLengthAction
+    | GetDataLengthSuccessAction
+    | GetDataLengthFailAction
+    | AddSelectedDataAction
+    | DeleteSelectedDataAction
+    | ExecuteProcessAction
+    | ExecuteProcessWipAction
+    | ExecuteProcessSuccessAction
+    | ExecuteProcessFailAction
+    | DestroyResultsAction;
diff --git a/src/app/search-multiple/store/search-multiple.effects.ts b/src/app/search-multiple/store/search-multiple.effects.ts
new file mode 100644
index 0000000000000000000000000000000000000000..57f7537ed650c5f2041eb64d1d5b47cb558e684b
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.effects.ts
@@ -0,0 +1,315 @@
+import { Injectable } from '@angular/core';
+import { HttpErrorResponse } from '@angular/common/http';
+
+import { ToastrService } from 'ngx-toastr';
+import { Effect, Actions, ofType } from '@ngrx/effects';
+import { Store, Action } from '@ngrx/store';
+import { of } from 'rxjs';
+import { map, tap, switchMap, withLatestFrom, catchError, delay } from 'rxjs/operators';
+
+import * as attributeActions from '../../metamodel/action/attribute.action';
+import * as criteriaActions from '../../metamodel/action/criteria.action';
+import * as outputActions from '../../metamodel/action/output.action';
+import * as searchActions from './search.action';
+import * as coneSearchActions from '../../shared/cone-search/store/cone-search.action';
+import * as fromMetamodel from '../../metamodel/reducers';
+import * as fromRouter from '@ngrx/router-store';
+import * as fromSearch from './search.reducer';
+import * as fromConeSearch from '../../shared/cone-search/store/cone-search.reducer';
+import * as utils from '../../shared/utils';
+import { SearchMultipleService } from './search.service';
+import { getCriterionStr } from '../../shared/utils';
+import { ConeSearch } from "../../shared/cone-search/store/model";
+
+@Injectable()
+export class SearchMultipleEffects {
+    constructor(
+        private actions$: Actions,
+        private searchService: SearchMultipleService,
+        private toastr: ToastrService,
+        private store$: Store<{
+            router: fromRouter.RouterReducerState<utils.RouterStateUrl>,
+            search: fromSearch.State,
+            metamodel: fromMetamodel.State,
+            coneSearch: fromConeSearch.State
+        }>
+    ) { }
+
+    @Effect()
+    initSearchByUrlAction$ = this.actions$.pipe(
+        ofType(searchActions.INIT_SEARCH_BY_URL),
+        withLatestFrom(this.store$),
+        switchMap(([action, state]) => {
+            if (state.search.pristine) {
+                const datasetName = state.router.state.params.dname;
+                const actions: Action[] = [
+                    new attributeActions.LoadAttributeSearchMetaAction(datasetName),
+                    new searchActions.SelectDatasetAction(datasetName),
+                    new criteriaActions.LoadCriteriaSearchMetaAction(datasetName),
+                    new outputActions.LoadOutputSearchMetaAction(datasetName)
+                ];
+                if (state.router.state.queryParams.s[0] === '1') {
+                    actions.push(new searchActions.CriteriaChecked());
+                }
+                if (state.router.state.queryParams.s[1] === '1') {
+                    actions.push(new searchActions.OutputChecked());
+                }
+                if (state.router.state.queryParams.s[2] === '1') {
+                    actions.push(new searchActions.ResultChecked());
+                }
+                return actions;
+            } else {
+                return of({ type: '[No Action] ' + searchActions.INIT_SEARCH_BY_URL });
+            }
+        })
+    );
+
+    @Effect()
+    newSearchAction$ = this.actions$.pipe(
+        ofType(searchActions.NEW_SEARCH),
+        map((action: searchActions.NewSearchAction) => new searchActions.SelectDatasetAction(action.payload))
+    );
+
+    @Effect()
+    loadDatasetAttributeListSuccessAction$ = this.actions$.pipe(
+        ofType(attributeActions.LOAD_ATTRIBUTE_SEARCH_META_SUCCESS),
+        withLatestFrom(this.store$),
+        switchMap(([action, state]) => {
+            const loadAttributeSearchMetaSuccessAction = action as attributeActions.LoadAttributeSearchMetaSuccessAction;
+
+            const actions: Action[] = [];
+
+            let defaultOutputList = loadAttributeSearchMetaSuccessAction.payload
+                .filter(attribute => attribute.selected && attribute.id_output_category)
+                .sort((a, b) => a.output_display - b.output_display)
+                .map(attribute => attribute.id);
+
+            if (state.router.state.queryParams.a) {
+                defaultOutputList = state.router.state.queryParams.a.split(';').map((o: string) => parseInt(o, 10));
+            }
+
+            actions.push(new searchActions.UpdateOutputListAction(defaultOutputList));
+
+            let defaultCriteriaList = loadAttributeSearchMetaSuccessAction.payload
+                .filter(attribute => attribute.id_criteria_family && attribute.search_type && attribute.min)
+                .map(attribute => {
+                    switch (attribute.search_type) {
+                        case 'field':
+                        case 'select':
+                        case 'datalist':
+                        case 'radio':
+                        case 'date':
+                        case 'date-time':
+                        case 'time':
+                            return { id: attribute.id, type: 'field', value: attribute.min.toString(), operator: attribute.operator };
+                        case 'list':
+                            return { id: attribute.id, type: 'list', values: attribute.min.toString().split('|') };
+                        case 'between':
+                        case 'between-date':
+                            return { id: attribute.id, type: 'between', min: attribute.min.toString(), max: attribute.max.toString() };
+                        case 'select-multiple':
+                        case 'checkbox':
+                            const msValues = attribute.min.toString().split('|');
+                            const options = attribute.options.filter(option => msValues.includes(option.value));
+                            return { id: attribute.id, type: 'multiple', options };
+                        case 'json':
+                            const [path, operator, value] = attribute.min.toString().split('|');
+                            return { id: attribute.id, type: 'json', path, operator, value };
+
+                        default:
+                            return null;
+                    }
+                });
+
+            if (state.router.state.queryParams.c) {
+                defaultCriteriaList = state.router.state.queryParams.c.split(';').map((c: string) => {
+                    const params = c.split('::');
+                    const attribute = loadAttributeSearchMetaSuccessAction.payload.find(a => a.id === parseInt(params[0], 10));
+                    switch (attribute.search_type) {
+                        case 'field':
+                        case 'select':
+                        case 'datalist':
+                        case 'radio':
+                        case 'date':
+                        case 'date-time':
+                        case 'time':
+                            return { id: parseInt(params[0], 10), type: 'field', operator: params[1], value: params[2] };
+                        case 'list':
+                            return { id: parseInt(params[0], 10), type: 'list', values: params[2].split('|') };
+                        case 'between':
+                        case 'between-date':
+                            if (params[1] === 'bw') {
+                                const bwValues = params[2].split('|');
+                                return { id: parseInt(params[0], 10), type: 'between', min: bwValues[0], max: bwValues[1] };
+                            } else if (params[1] === 'gte') {
+                                return { id: parseInt(params[0], 10), type: 'between', min: params[2], max: null };
+                            } else {
+                                return { id: parseInt(params[0], 10), type: 'between', min: null, max: params[2] };
+                            }
+                        case 'select-multiple':
+                        case 'checkbox':
+                            const msValues = params[2].split('|');
+                            const options = attribute.options.filter(option => msValues.includes(option.value));
+                            return { id: parseInt(params[0], 10), type: 'multiple', options };
+                        case 'json':
+                            const [path, operator, value] = params[2].split('|');
+                            return { id: parseInt(params[0], 10), type: 'json', path, operator, value };
+
+                        default:
+                            return null;
+                    }
+                });
+            }
+
+            actions.push(new searchActions.UpdateCriteriaListAction(defaultCriteriaList));
+            
+            if (state.router.state.queryParams.cs) {
+                const params = state.router.state.queryParams.cs.split(':');
+                const coneSearch: ConeSearch = {
+                    ra: parseFloat(params[0]),
+                    dec: parseFloat(params[1]),
+                    radius: parseInt(params[2], 10)
+                };
+                actions.push(new searchActions.IsConeSearchAddedAction(true));
+                actions.push(new coneSearchActions.AddConeSearchAction(coneSearch));
+            }
+
+            return actions;
+        })
+    );
+
+    @Effect()
+    retrieveDataAction$ = this.actions$.pipe(
+        ofType(searchActions.RETRIEVE_DATA),
+        withLatestFrom(this.store$),
+        switchMap(([action, state]) => {
+            const retrieveDataAction = action as searchActions.RetrieveDataAction;
+            let query = state.search.datasetName + '?a=' + state.search.outputList.join(';');
+            if (state.search.criteriaList.length > 0) {
+                query += '&c=' + state.search.criteriaList.map(criterion => getCriterionStr(criterion)).join(';');
+            }
+            if (state.search.coneSearchAdded) {
+                query += '&cs=' + state.coneSearch.coneSearch.ra + ':' + state.coneSearch.coneSearch.dec + ':' + state.coneSearch.coneSearch.radius;
+            }
+            query += '&p=' + retrieveDataAction.payload[1] + ':' + retrieveDataAction.payload[0];
+            query += '&o=' + retrieveDataAction.payload[2] + ':' + retrieveDataAction.payload[3];
+            return this.searchService.retrieveData(query).pipe(
+                map((searchData: any[]) => new searchActions.RetrieveDataSuccessAction(searchData)),
+                catchError(() => of(new searchActions.RetrieveDataFailAction()))
+            );
+        })
+    );
+
+    @Effect({ dispatch: false })
+    retrieveDataFailAction$ = this.actions$.pipe(
+        ofType(searchActions.RETRIEVE_DATA_FAIL),
+        tap(_ => this.toastr.error('Loading Failed!', 'The search data loading failed'))
+    );
+
+    @Effect()
+    getDataLengthAction$ = this.actions$.pipe(
+        ofType(searchActions.GET_DATA_LENGTH),
+        withLatestFrom(this.store$),
+        switchMap(([action, state]) => {
+            let query = state.search.datasetName + '?a=count';
+            if (state.search.criteriaList.length > 0) {
+                query += '&c=' + state.search.criteriaList.map(criterion => getCriterionStr(criterion)).join(';');
+            }
+            if (state.search.coneSearchAdded) {
+                query += '&cs=' + state.coneSearch.coneSearch.ra + ':' + state.coneSearch.coneSearch.dec + ':' + state.coneSearch.coneSearch.radius;
+            }
+            return this.searchService.getDataLength(query).pipe(
+                map((response: { nb: number }[]) => new searchActions.GetDataLengthSuccessAction(response[0].nb)),
+                catchError(() => of(new searchActions.GetDataLengthFailAction()))
+            );
+        })
+    );
+
+    @Effect({ dispatch: false })
+    getDataLengthFailAction$ = this.actions$.pipe(
+        ofType(searchActions.GET_DATA_LENGTH_FAIL),
+        tap(_ => this.toastr.error('Loading Failed!', 'The data length loading failed'))
+    );
+
+    @Effect()
+    executeProcessAction$ = this.actions$.pipe(
+        ofType(searchActions.EXECUTE_PROCESS),
+        withLatestFrom(this.store$),
+        switchMap(([action, state]) => {
+            const executeProcessAction = action as searchActions.ExecuteProcessAction;
+            const dname = state.search.datasetName;
+            let query = '?a=' + state.search.outputList.join(';');
+            query += '&c=';
+            query += state.metamodel.attribute.datasetAttributeList.find(a => a.search_flag === 'ID').id;
+            query += '::in::';
+            query += state.search.selectedData.join('|');
+            return this.searchService.executeProcess(executeProcessAction.payload, dname, query).pipe(
+                map((res: any) => new searchActions.ExecuteProcessWipAction(res.message)),
+                catchError(() => of(new searchActions.ExecuteProcessFailAction()))
+            );
+        })
+    );
+
+    @Effect()
+    executeProcessWipAction$ = this.actions$.pipe(
+        ofType(searchActions.EXECUTE_PROCESS_WIP),
+        withLatestFrom(this.store$),
+        switchMap(([action, state]) => {
+            const executeProcessWipAction = action as searchActions.ExecuteProcessWipAction;
+            const idProcess: string = executeProcessWipAction.payload;
+            return this.searchService.checkProcess(idProcess).pipe(
+                map(_ => {
+                    return new searchActions.ExecuteProcessSuccessAction(idProcess);
+                }),
+                catchError((err: HttpErrorResponse) => {
+                    if (err.status === 404) {
+                        return of(new searchActions.ExecuteProcessWipAction(idProcess)).pipe(delay(5000));
+                    }
+                    return of(new searchActions.ExecuteProcessFailAction());
+                }));
+        })
+    );
+
+    @Effect({ dispatch: false })
+    executeProcessFailAction$ = this.actions$.pipe(
+        ofType(searchActions.EXECUTE_PROCESS_FAIL),
+        tap(_ => this.toastr.error('Action Failed!', 'The process failed'))
+    );
+
+    // @Effect()
+    // retrieveCoordinatesAction$ = this.actions$.pipe(
+    //     ofType(searchActions.RETRIEVE_COORDINATES),
+    //     withLatestFrom(this.store$),
+    //     switchMap(([action, state]) => {
+    //         const retrieveCoordinatesAction = action as searchActions.RetrieveCoordinatesAction;
+    //         return this.searchService.retrieveCoordinates(retrieveCoordinatesAction.payload).pipe(
+    //             map((response) => {
+    //                 const parser = new DOMParser();
+    //                 const xml = parser.parseFromString(response,'text/xml');
+    //                 if (xml.getElementsByTagName('Resolver').length === 0) {
+    //                     const name = xml.getElementsByTagName('name')[0].childNodes[0].nodeValue;
+    //                     return new searchActions.RetrieveCoordinatesFailAction(name);
+    //                 }
+    //                 const name = xml.getElementsByTagName('name')[0].childNodes[0].nodeValue;
+    //                 const ra = +xml.getElementsByTagName('jradeg')[0].childNodes[0].nodeValue;
+    //                 const dec = +xml.getElementsByTagName('jdedeg')[0].childNodes[0].nodeValue;
+    //                 return new searchActions.RetrieveCoordinatesSuccessAction({name, ra, dec});
+    //             }),
+    //             catchError(() => of(new searchActions.RetrieveCoordinatesFailAction(null)))
+    //         );
+    //     })
+    // );
+    //
+    // @Effect({ dispatch: false })
+    // retrieveCoordinatesFailAction$ = this.actions$.pipe(
+    //     ofType(searchActions.RETRIEVE_COORDINATES_FAIL),
+    //     tap(action => {
+    //         const retrieveCoordinatesFailAction = action as searchActions.RetrieveCoordinatesFailAction;
+    //         if (retrieveCoordinatesFailAction.payload) {
+    //             this.toastr.error(retrieveCoordinatesFailAction.payload + ' not found');
+    //         } else {
+    //             this.toastr.error('Connection to Sesame Name Resolver failed', 'Resolver Failed!');
+    //         }
+    //     })
+    // );
+}
diff --git a/src/app/search-multiple/store/search-multiple.reducer.spec.ts b/src/app/search-multiple/store/search-multiple.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73a7b2c20b9999d1510efc4c86902096aed25f66
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.reducer.spec.ts
@@ -0,0 +1,651 @@
+import * as fromSearch from './search.reducer';
+import * as searchActions from './search.action';
+import { CRITERIA_LIST } from '../../../settings/test-data'
+import { FieldCriterion } from './model';
+
+describe('[Search] Reducer', () => {
+    it('should return init state', () => {
+        const { initialState } = fromSearch;
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(state).toBe(initialState);
+    });
+
+    it('should change the currentStep', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.ChangeStepAction('toto');
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toEqual('toto');
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set the datasetName and change pristine', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.SelectDatasetAction('toto');
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeFalsy();
+        expect(state.currentStep).toBeNull();
+        expect(state.datasetName).toBe('toto');
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set currentStep to "dataset"', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.NewSearchAction('toto');
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toEqual('dataset');
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set criteriaStepChecked to true', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.CriteriaChecked();
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeTruthy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set outputStepChecked to true', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.OutputChecked();
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeTruthy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set resultStepChecked to true', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.ResultChecked();
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeTruthy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set coneSearchAdded to true', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.IsConeSearchAddedAction(true);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeTruthy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+
+    it('should set criteriaList', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.UpdateCriteriaListAction(CRITERIA_LIST);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(2);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should add criterion to criteriaList', () => {
+        const criterion: FieldCriterion = { id: 3, type: 'field', operator: 'eq', value: 'fd_crit_3' };
+        const { initialState } = fromSearch;
+        const action = new searchActions.AddCriterionAction(criterion);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(1);
+        expect(state.criteriaList[0].id).toEqual(3);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should remove criterion to criteriaList', () => {
+        const criterion: FieldCriterion = { id: 2, type: 'field', operator: 'eq', value: 'fd_crit_2' };
+        const initialState = { ...fromSearch.initialState, criteriaList: CRITERIA_LIST };
+        const action = new searchActions.DeleteCriterionAction(criterion.id);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(1);
+        expect(state.criteriaList[0].id).toEqual(1);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set outputList', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.UpdateOutputListAction([1, 2]);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(2);
+        expect(state.outputList).toContain(1);
+        expect(state.outputList).toContain(2);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set outputListEmpty to false', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.OutputListEmptyAction(false);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeFalsy();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set searchData', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.RetrieveDataSuccessAction(['data_1', 'data_2']);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData.length).toBe(2);
+        expect(state.searchData).toContain('data_1');
+        expect(state.searchData).toContain('data_2');
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set dataLength', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.GetDataLengthSuccessAction(12);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBe(12);
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should add data to selectedData', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.AddSelectedDataAction(1);
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(1);
+        expect(state.selectedData).toContain(1);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should remove data to selectedData', () => {
+        const initialState = { ...fromSearch.initialState, selectedData: ['data_1', 'data_2'] };
+        const action = new searchActions.DeleteSelectedDataAction('data_2');
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(1);
+        expect(state.selectedData).toContain('data_1');
+        expect(state.selectedData).not.toContain('data_2');
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set processWip to true and processDone to false', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.ExecuteProcessAction('process_type');
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeTruthy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set processId', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.ExecuteProcessWipAction('toto');
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBe('toto');
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set processWip to false and processDone to true', () => {
+        const { initialState } = fromSearch;
+        const action = new searchActions.ExecuteProcessSuccessAction('toto');
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeTruthy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should unset processId and set processWip and processDone to false', () => {
+        const initialState = {
+            ...fromSearch.initialState,
+            processId: 'toto',
+            processWip: true,
+            processDone: true
+        };
+        const action = new searchActions.ExecuteProcessFailAction();
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should unset searchData and dataLength', () => {
+        const initialState = {
+            ...fromSearch.initialState,
+            searchData: ['toto', 'titi', 'tutu'],
+            dataLength: 3
+        };
+        const action = new searchActions.DestroyResultsAction();
+        const state = fromSearch.reducer(initialState, action);
+
+        expect(state.pristine).toBeTruthy();
+        expect(state.currentStep).toBeNull()
+        expect(state.datasetName).toBeNull();
+        expect(state.criteriaStepChecked).toBeFalsy();
+        expect(state.outputStepChecked).toBeFalsy();
+        expect(state.resultStepChecked).toBeFalsy();
+        expect(state.coneSearchAdded).toBeFalsy();
+        expect(state.criteriaList.length).toEqual(0);
+        expect(state.outputList.length).toEqual(0);
+        expect(state.searchData).toBeNull();
+        expect(state.dataLength).toBeNull();
+        expect(state.selectedData.length).toEqual(0);
+        expect(state.processWip).toBeFalsy();
+        expect(state.processDone).toBeFalsy();
+        expect(state.processId).toBeNull();
+        expect(state.outputListEmpty).toBeNull();
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should get pristine', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getPristine(state)).toBeTruthy();
+    });
+
+    it('should get currentStep', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getCurrentStep(state)).toBeNull();
+    });
+
+    it('should get datasetName', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getDatasetName(state)).toBeNull();
+    });
+
+    it('should get criteriaStepChecked', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getCriteriaStepChecked(state)).toBeFalsy();
+    });
+
+    it('should get outputStepChecked', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getOutputStepChecked(state)).toBeFalsy();
+    });
+
+    it('should get resultStepChecked', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getResultStepChecked(state)).toBeFalsy();
+    });
+
+    it('should get coneSearchAdded', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getIsConeSearchAdded(state)).toBeFalsy();
+    });
+
+    it('should get criteriaList', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getCriteriaList(state).length).toEqual(0);
+    });
+
+    it('should get outputList', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getOutputList(state).length).toEqual(0);
+    });
+
+    it('should get outputListEmpty', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getOutputListEmpty(state)).toBeNull();
+    });
+
+    it('should get searchData', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getSearchData(state)).toBeNull();
+    });
+
+    it('should get dataLength', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getDataLength(state)).toBeNull();
+    });
+
+    it('should get selectedData', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getSelectedData(state).length).toEqual(0);
+    });
+
+    it('should get processWip', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getProcessWip(state)).toBeFalsy();
+    });
+
+    it('should get processDone', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getProcessDone(state)).toBeFalsy();
+    });
+
+    it('should get processId', () => {
+        const action = {} as searchActions.Actions;
+        const state = fromSearch.reducer(undefined, action);
+
+        expect(fromSearch.getProcessId(state)).toBeNull();
+    });
+});
diff --git a/src/app/search-multiple/store/search-multiple.reducer.ts b/src/app/search-multiple/store/search-multiple.reducer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..75c7d65b9e1762b549fa9c7d574f11b312c5aba0
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.reducer.ts
@@ -0,0 +1,212 @@
+import * as actions from './search.action';
+
+import { Criterion } from './model';
+// import { Criterion ,Resolver, ConeSearch } from './model';
+
+export interface State {
+    pristine: boolean;
+    currentStep: string;
+    datasetName: string;
+    criteriaStepChecked: boolean;
+    outputStepChecked: boolean;
+    resultStepChecked: boolean;
+    coneSearchAdded: boolean;
+    criteriaList: Criterion[];
+    outputList: number[];
+    searchData: any[];
+    dataLength: number;
+    selectedData: any[];
+    processWip: boolean;
+    processDone: boolean;
+    processId: string;
+    outputListEmpty: boolean;
+}
+
+export const initialState: State = {
+    pristine: true,
+    currentStep: null,
+    datasetName: null,
+    criteriaStepChecked: false,
+    outputStepChecked: false,
+    resultStepChecked: false,
+    coneSearchAdded: false,
+    criteriaList: [],
+    outputList: [],
+    searchData: null,
+    dataLength: null,
+    selectedData: [],
+    processWip: false,
+    processDone: false,
+    processId: null,
+    outputListEmpty: null
+};
+
+export function reducer(state: State = initialState, action: actions.Actions): State {
+    switch (action.type) {
+        case actions.CHANGE_STEP:
+            const currentStep: string = action.payload;
+            return {
+                ...state,
+                currentStep
+            };
+
+        case actions.SELECT_DATASET:
+            const datasetName: string = action.payload;
+            return {
+                ...state,
+                pristine: false,
+                datasetName
+            };
+
+        case actions.NEW_SEARCH:
+            return {
+                ...initialState,
+                currentStep: 'dataset'
+            };
+
+        case actions.CRITERIA_CHECKED:
+            return {
+                ...state,
+                criteriaStepChecked: true
+            };
+
+        case actions.OUTPUT_CHECKED:
+            return {
+                ...state,
+                outputStepChecked: true
+            };
+
+        case actions.RESULT_CHECKED:
+            return {
+                ...state,
+                resultStepChecked: true
+            };
+
+        case actions.IS_CONE_SEARCH_ADDED:
+            const coneSearchAdded: boolean = action.payload;
+
+            return {
+                ...state,
+                coneSearchAdded
+            };
+
+        case actions.UPDATE_CRITERIA_LIST:
+            const criteriaList: Criterion[] = action.payload;
+            return {
+                ...state,
+                criteriaList
+            };
+
+        case actions.ADD_CRITERION:
+            const criterion: Criterion = action.payload;
+            return {
+                ...state,
+                criteriaList: [...state.criteriaList, criterion]
+            };
+
+        case actions.DELETE_CRITERION:
+            const id: number = action.payload;
+            return {
+                ...state,
+                criteriaList: [...state.criteriaList.filter(c => c.id !== id)]
+            };
+
+        case actions.UPDATE_OUTPUT_LIST:
+            const outputList: number[] = action.payload;
+            return {
+                ...state,
+                outputList
+            };
+
+        case actions.OUTPUT_LIST_EMPTY:
+            const outputListEmpty: boolean = action.payload;
+            return {
+                ...state,
+                outputListEmpty
+            };
+
+        case actions.RETRIEVE_DATA_SUCCESS:
+            const searchData: any[] = action.payload;
+            return {
+                ...state,
+                searchData
+            };
+
+        case actions.GET_DATA_LENGTH_SUCCESS:
+            const dataLength: number = action.payload;
+            return {
+                ...state,
+                dataLength
+            };
+
+        case actions.ADD_SELECTED_DATA:
+            const addData: number | string = action.payload;
+            return {
+                ...state,
+                selectedData: [...state.selectedData, addData]
+            };
+
+        case actions.DELETE_SELECTED_DATA:
+            const deleteData: number | string = action.payload;
+            return {
+                ...state,
+                selectedData: [...state.selectedData.filter(d => d !== deleteData)]
+            };
+
+        case actions.EXECUTE_PROCESS:
+            return {
+                ...state,
+                processWip: true,
+                processDone: false
+            };
+
+        case actions.EXECUTE_PROCESS_WIP:
+            const processId: string = action.payload;
+            return {
+                ...state,
+                processId
+            };
+
+        case actions.EXECUTE_PROCESS_SUCCESS:
+            return {
+                ...state,
+                processWip: false,
+                processDone: true
+            };
+
+        case actions.EXECUTE_PROCESS_FAIL:
+            return {
+                ...state,
+                processWip: false,
+                processDone: false,
+                processId: null
+            };
+
+        case actions.DESTROY_RESULTS:
+            return {
+                ...state,
+                searchData: null,
+                dataLength: null
+            };
+
+        default:
+            return state;
+    }
+}
+
+export const getPristine = (state: State) => state.pristine;
+export const getCurrentStep = (state: State) => state.currentStep;
+export const getDatasetName = (state: State) => state.datasetName;
+export const getCriteriaStepChecked = (state: State) => state.criteriaStepChecked;
+export const getOutputStepChecked = (state: State) => state.outputStepChecked;
+export const getResultStepChecked = (state: State) => state.resultStepChecked;
+export const getIsConeSearchAdded = (state: State) => state.coneSearchAdded;
+export const getCriteriaList = (state: State) => state.criteriaList;
+export const getOutputList = (state: State) => state.outputList;
+export const getOutputListEmpty = (state: State) => state.outputListEmpty;
+export const getSearchData = (state: State) => state.searchData;
+export const getDataLength = (state: State) => state.dataLength;
+export const getSelectedData = (state: State) => state.selectedData;
+export const getProcessWip = (state: State) => state.processWip;
+export const getProcessDone = (state: State) => state.processDone;
+export const getProcessId = (state: State) => state.processId;
diff --git a/src/app/search-multiple/store/search-multiple.selector.spec.ts b/src/app/search-multiple/store/search-multiple.selector.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fd9df0a5c752d5f27b821cf453c17bda7e200dd9
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.selector.spec.ts
@@ -0,0 +1,158 @@
+import * as searchSelector from './search.selector';
+import * as fromSearch from './search.reducer';
+import * as fromConeSearch from '../../shared/cone-search/store/cone-search.reducer';
+import { Criterion } from './model';
+import { CRITERIA_LIST } from 'src/settings/test-data';
+import { ConeSearch } from "../../shared/cone-search/store/model";
+
+describe('[Search] Selector', () => {
+    it('should get pristine', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getPristine(state)).toBeTruthy();
+    });
+
+    it('should get currentStep', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getCurrentStep(state)).toBeNull();
+    });
+
+    it('should get datasetName', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getDatasetName(state)).toBeNull();
+    });
+
+    it('should get criteriaStepChecked', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getCriteriaStepChecked(state)).toBeFalsy();
+    });
+
+    it('should get outputStepChecked', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getOutputStepChecked(state)).toBeFalsy();
+    });
+
+    it('should get resultStepChecked', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getResultStepChecked(state)).toBeFalsy();
+    });
+
+    it('should get coneSearchAdded', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getIsConeSearchAdded(state)).toBeFalsy();
+    });
+
+    it('should get criteriaList', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getCriteriaList(state).length).toEqual(0);
+    });
+
+    it('should get outputList', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getOutputList(state).length).toEqual(0);
+    });
+
+    it('should get searchData', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getSearchData(state)).toBeNull();
+    });
+
+    it('should get dataLength', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getDataLength(state)).toBeNull();
+    });
+
+    it('should get selectedData', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getSelectedData(state).length).toEqual(0);
+    });
+
+    it('should get queryParams without criteria', () => {
+        const outputList: number[] = [1, 2];
+        const state = {
+            search: {
+                ...fromSearch.initialState,
+                outputList
+            },
+            coneSearch: { ...fromConeSearch.initialState }
+        };
+        const expected = { s: '000', a: '1;2' };
+
+        expect(searchSelector.getQueryParams(state)).toEqual(expected);
+    });
+
+    it('should get queryParams with criteria', () => {
+        const outputList: number[] = [1, 2];
+        const criteriaList: Criterion[] = CRITERIA_LIST;
+        const state = {
+            search: {
+                ...fromSearch.initialState,
+                outputList,
+                criteriaList
+            },
+            coneSearch: { ...fromConeSearch.initialState }
+        };
+        const expected = { s: '000', a: '1;2', c: '1::eq::fd_crit_1;2::eq::fd_crit_2' };
+
+        expect(searchSelector.getQueryParams(state)).toEqual(expected);
+    });
+
+    it('should get queryParams with cone search', () => {
+        const outputList: number[] = [1, 2];
+        const coneSearchAdded: boolean = true;
+        const coneSearch: ConeSearch = { ra: 3, dec: 4, radius: 5 };
+        const state = {
+            search: {
+                ...fromSearch.initialState,
+                outputList,
+                coneSearchAdded
+            },
+            coneSearch: {
+                ...fromConeSearch.initialState,
+                coneSearch
+            }
+        };
+        const expected = { s: '000', a: '1;2', cs: '3:4:5' };
+
+        expect(searchSelector.getQueryParams(state)).toEqual(expected);
+    });
+
+    it('should get queryParams with checked steps', () => {
+        const criteriaStepChecked: boolean = true;
+        const outputStepChecked: boolean = true;
+        const resultStepChecked: boolean = true;
+        const outputList: number[] = [1, 2];
+        const state = {
+            search: {
+                ...fromSearch.initialState,
+                criteriaStepChecked,
+                outputStepChecked,
+                resultStepChecked,
+                outputList
+            },
+            coneSearch: { ...fromConeSearch.initialState }
+        };
+        const expected = { s: '111', a: '1;2' };
+
+        expect(searchSelector.getQueryParams(state)).toEqual(expected);
+    });
+
+    it('should get processWip', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getProcessWip(state)).toBeFalsy();
+    });
+
+    it('should get processDone', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getProcessDone(state)).toBeFalsy();
+    });
+
+    it('should get processId', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getProcessId(state)).toBeNull();
+    });
+
+    it('should get outputListEmpty', () => {
+        const state = { search: { ...fromSearch.initialState }};
+        expect(searchSelector.getOutputListEmpty(state)).toBeNull();
+    });
+});
\ No newline at end of file
diff --git a/src/app/search-multiple/store/search-multiple.selector.ts b/src/app/search-multiple/store/search-multiple.selector.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ab19fd506edf6183b0128aa38f36de3b5f93a315
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.selector.ts
@@ -0,0 +1,129 @@
+import { createSelector, createFeatureSelector } from '@ngrx/store';
+
+import * as search from './search.reducer';
+import { Criterion, SearchQueryParams } from './model';
+import { getCriterionStr } from '../../shared/utils';
+import { getConeSearch } from "../../shared/cone-search/store/cone-search.selector";
+import { ConeSearch } from "../../shared/cone-search/store/model";
+
+export const getSearchState = createFeatureSelector<search.State>('search');
+
+export const getPristine = createSelector(
+    getSearchState,
+    search.getPristine
+);
+
+export const getCurrentStep = createSelector(
+    getSearchState,
+    search.getCurrentStep
+);
+
+export const getDatasetName = createSelector(
+    getSearchState,
+    search.getDatasetName
+);
+
+export const getCriteriaStepChecked = createSelector(
+    getSearchState,
+    search.getCriteriaStepChecked
+);
+
+export const getOutputStepChecked = createSelector(
+    getSearchState,
+    search.getOutputStepChecked
+);
+
+export const getResultStepChecked = createSelector(
+    getSearchState,
+    search.getResultStepChecked
+);
+
+export const getIsConeSearchAdded = createSelector(
+    getSearchState,
+    search.getIsConeSearchAdded
+);
+
+export const getCriteriaList = createSelector(
+    getSearchState,
+    search.getCriteriaList
+);
+
+export const getOutputList = createSelector(
+    getSearchState,
+    search.getOutputList
+);
+
+export const getSearchData = createSelector(
+    getSearchState,
+    search.getSearchData
+);
+
+export const getDataLength = createSelector(
+    getSearchState,
+    search.getDataLength
+);
+
+export const getSelectedData = createSelector(
+    getSearchState,
+    search.getSelectedData
+);
+
+export const getQueryParams = createSelector(
+    getIsConeSearchAdded,
+    getConeSearch,
+    getCriteriaList,
+    getOutputList,
+    getCriteriaStepChecked,
+    getOutputStepChecked,
+    getResultStepChecked,
+    (
+        isConeSearchAdded: boolean,
+        coneSearch: ConeSearch,
+        criteriaList: Criterion[],
+        outputList: number[],
+        criteriaStepChecked: boolean,
+        outputStepChecked: boolean,
+        resultStepChecked: boolean) => {
+        let step = '';
+        step += (criteriaStepChecked) ? '1' : '0';
+        step += (outputStepChecked) ? '1' : '0';
+        step += (resultStepChecked) ? '1' : '0';
+        let queryParams: SearchQueryParams = {
+            s: step,
+            a: outputList.join(';')
+        };
+        if (isConeSearchAdded) {
+            queryParams = {
+                ...queryParams,
+                cs: coneSearch.ra + ':' + coneSearch.dec + ':' + coneSearch.radius
+            };
+        }
+        if (criteriaList.length > 0) {
+            queryParams = {
+                ...queryParams,
+                c: criteriaList.map(criterion => getCriterionStr(criterion)).join(';')
+            };
+        }
+        return queryParams;
+    }
+);
+
+export const getProcessWip = createSelector(
+    getSearchState,
+    search.getProcessWip
+);
+
+export const getProcessDone = createSelector(
+    getSearchState,
+    search.getProcessDone
+);
+
+export const getProcessId = createSelector(
+    getSearchState,
+    search.getProcessId
+);
+
+export const getOutputListEmpty = createSelector(
+    getSearchState,
+    search.getOutputListEmpty
+);
diff --git a/src/app/search-multiple/store/search-multiple.service.ts b/src/app/search-multiple/store/search-multiple.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..467dfd76ecebbf6962a450d1638e0d1ff5bb51b2
--- /dev/null
+++ b/src/app/search-multiple/store/search-multiple.service.ts
@@ -0,0 +1,34 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+
+import { environment } from '../../../environments/environment';
+
+@Injectable()
+export class SearchMultipleService {
+    API_PATH: string = environment.apiUrl;
+    instanceName: string = environment.instanceName;
+
+    constructor(private http: HttpClient) { }
+
+    retrieveData(query: string) {
+        return this.http.get<any[]>(this.API_PATH + '/search/' + query);
+    }
+
+    getDataLength(query: string) {
+        return this.http.get<{ nb: number }[]>(this.API_PATH + '/search/' + query);
+    }
+
+    executeProcess(typeProcess: string, dname: string, query: string) {
+        const url = this.API_PATH + '/service/' + this.instanceName + '/' + dname + '/' + typeProcess + query;
+        return this.http.get<any>(url);
+    }
+
+    checkProcess(id: string) {
+        return this.http.head<any>('http://0.0.0.0:8085/' + id + '.csv');
+    }
+
+    // retrieveCoordinates(name: string) {
+    //     const url = 'https://cdsweb.u-strasbg.fr/cgi-bin/nph-sesame/-ox/NSV?' + name;
+    //     return this.http.get(url, { responseType: 'text' });
+    // }
+}
diff --git a/src/app/search/store/search.effects.ts b/src/app/search/store/search.effects.ts
index 83eafbc8b4ef4c26df81205189ea6e8b39adc912..d1df15775d6cbc1fed38c5de5e4f0c0ddd5611f1 100644
--- a/src/app/search/store/search.effects.ts
+++ b/src/app/search/store/search.effects.ts
@@ -275,41 +275,4 @@ export class SearchEffects {
         ofType(searchActions.EXECUTE_PROCESS_FAIL),
         tap(_ => this.toastr.error('Action Failed!', 'The process failed'))
     );
-
-    // @Effect()
-    // retrieveCoordinatesAction$ = this.actions$.pipe(
-    //     ofType(searchActions.RETRIEVE_COORDINATES),
-    //     withLatestFrom(this.store$),
-    //     switchMap(([action, state]) => {
-    //         const retrieveCoordinatesAction = action as searchActions.RetrieveCoordinatesAction;
-    //         return this.searchService.retrieveCoordinates(retrieveCoordinatesAction.payload).pipe(
-    //             map((response) => {
-    //                 const parser = new DOMParser();
-    //                 const xml = parser.parseFromString(response,'text/xml');
-    //                 if (xml.getElementsByTagName('Resolver').length === 0) {
-    //                     const name = xml.getElementsByTagName('name')[0].childNodes[0].nodeValue;
-    //                     return new searchActions.RetrieveCoordinatesFailAction(name);
-    //                 }
-    //                 const name = xml.getElementsByTagName('name')[0].childNodes[0].nodeValue;
-    //                 const ra = +xml.getElementsByTagName('jradeg')[0].childNodes[0].nodeValue;
-    //                 const dec = +xml.getElementsByTagName('jdedeg')[0].childNodes[0].nodeValue;
-    //                 return new searchActions.RetrieveCoordinatesSuccessAction({name, ra, dec});
-    //             }),
-    //             catchError(() => of(new searchActions.RetrieveCoordinatesFailAction(null)))
-    //         );
-    //     })
-    // );
-    //
-    // @Effect({ dispatch: false })
-    // retrieveCoordinatesFailAction$ = this.actions$.pipe(
-    //     ofType(searchActions.RETRIEVE_COORDINATES_FAIL),
-    //     tap(action => {
-    //         const retrieveCoordinatesFailAction = action as searchActions.RetrieveCoordinatesFailAction;
-    //         if (retrieveCoordinatesFailAction.payload) {
-    //             this.toastr.error(retrieveCoordinatesFailAction.payload + ' not found');
-    //         } else {
-    //             this.toastr.error('Connection to Sesame Name Resolver failed', 'Resolver Failed!');
-    //         }
-    //     })
-    // );
 }
diff --git a/src/app/search/store/search.service.ts b/src/app/search/store/search.service.ts
index 9af89f3be8a61db425bf348b537c1c83b09cde36..bb16196f8c17849f6f8bc56c14181c023bfba4dd 100644
--- a/src/app/search/store/search.service.ts
+++ b/src/app/search/store/search.service.ts
@@ -26,9 +26,4 @@ export class SearchService {
     checkProcess(id: string) {
         return this.http.head<any>('http://0.0.0.0:8085/' + id + '.csv');
     }
-
-    // retrieveCoordinates(name: string) {
-    //     const url = 'https://cdsweb.u-strasbg.fr/cgi-bin/nph-sesame/-ox/NSV?' + name;
-    //     return this.http.get(url, { responseType: 'text' });
-    // }
 }