diff --git a/client/src/app/instance/instance.component.ts b/client/src/app/instance/instance.component.ts
index 848e5e147f0409270a9585823b1b4157ad1177ce..6d2d31467394751078d5b9c14dd36ac4b0fee2bd 100644
--- a/client/src/app/instance/instance.component.ts
+++ b/client/src/app/instance/instance.component.ts
@@ -7,13 +7,14 @@
  * file that was distributed with this source code.
  */
 
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
 import { Observable } from 'rxjs';
 import { Store } from '@ngrx/store';
 
 import { UserProfile } from 'src/app/auth/user-profile.model';
 import * as authActions from 'src/app/auth/auth.actions';
 import * as authSelector from 'src/app/auth/auth.selector';
+import * as metamodelActions from './store/actions/metamodel.actions';
 
 @Component({
     selector: 'app-instance',
@@ -23,7 +24,7 @@ import * as authSelector from 'src/app/auth/auth.selector';
  * @class
  * @classdesc Instance container
  */
-export class InstanceComponent {
+export class InstanceComponent implements OnInit {
     public links = [
         { label: 'Home', icon: 'fas fa-home', routerLink: 'home' },
         { label: 'Search', icon: 'fas fa-search', routerLink: 'search' },
@@ -40,6 +41,11 @@ export class InstanceComponent {
         this.userRoles = store.select(authSelector.selectUserRoles);
     }
 
+    ngOnInit() {
+        // Load datasetList, datasetFamilyList, SurveyList
+        Promise.resolve(null).then(() => this.store.dispatch(metamodelActions.loadInstanceMetamodel()));
+    }
+
     login(): void {
         this.store.dispatch(authActions.login());
     }
diff --git a/client/src/app/instance/instance.reducer.ts b/client/src/app/instance/instance.reducer.ts
index 1c3ad08a7cfc928d6487b972d50fcb407d172fbc..7b96c8070d7eb46a76021f9d8ad4732443bd2435 100644
--- a/client/src/app/instance/instance.reducer.ts
+++ b/client/src/app/instance/instance.reducer.ts
@@ -9,18 +9,23 @@
 
 import { combineReducers, createFeatureSelector } from '@ngrx/store';
 
+import { RouterReducerState } from 'src/app/custom-route-serializer';
+import * as metamodel from './store/reducers/metamodel.reducer';
 import * as search from './store/reducers/search.reducer';
 import * as samp from './store/reducers/samp.reducer';
 
 export interface State {
+    metamodel: metamodel.State,
     search: search.State,
     samp: samp.State;
 }
 
 const reducers = {
+    metamodel: metamodel.metamodelReducer,
     search: search.searchReducer,
     samp: samp.sampReducer
 };
 
 export const instanceReducer = combineReducers(reducers);
 export const getInstanceState = createFeatureSelector<State>('instance');
+export const selectRouterState = createFeatureSelector<RouterReducerState>('router');
diff --git a/client/src/app/instance/search/components/dataset/dataset-card.component.html b/client/src/app/instance/search/components/dataset/dataset-card.component.html
index fbe4f48acf8f1af9f0c566bb99e7f0daf557f07d..190c9bc953e14a62ffc4528a79053ed03dece876 100644
--- a/client/src/app/instance/search/components/dataset/dataset-card.component.html
+++ b/client/src/app/instance/search/components/dataset/dataset-card.component.html
@@ -24,7 +24,8 @@
                 </div>
             </div>
             <div class="col-auto">
-                <button *ngIf="dataset.name !== datasetSelected" routerLink="/instance/{{ instanceSelected }}/search/dataset/{{ dataset.name }}"
+                <button *ngIf="dataset.name !== datasetSelected"
+                    (click)="selectDataset(dataset.name)"
                     class="btn btn-outline-secondary">
                     Select
                 </button>
diff --git a/client/src/app/instance/search/components/dataset/dataset-card.component.ts b/client/src/app/instance/search/components/dataset/dataset-card.component.ts
index 6eac1690b827ce9bb3742b340500769029e51935..ffeb52d4c33d61435f42d1ff21d8b5830f762156 100644
--- a/client/src/app/instance/search/components/dataset/dataset-card.component.ts
+++ b/client/src/app/instance/search/components/dataset/dataset-card.component.ts
@@ -7,7 +7,8 @@
  * file that was distributed with this source code.
  */
 
-import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
+import { Component, Input, ChangeDetectionStrategy, Output, EventEmitter } from '@angular/core';
+import { Router } from '@angular/router';
 
 import { Survey, Dataset } from 'src/app/metamodel/models';
 
@@ -25,5 +26,11 @@ export class DatasetCardComponent {
     @Input() dataset: Dataset;
     @Input() instanceSelected: string;
     @Input() datasetSelected: string;
+
+    constructor(private router: Router) { }
+
+    selectDataset(datasetName: string) {
+        this.router.routeReuseStrategy.shouldReuseRoute = () => false;
+        this.router.navigate([`/instance/${this.instanceSelected}/search/dataset/${datasetName}`]);
+    }
 }
- 
\ No newline at end of file
diff --git a/client/src/app/instance/search/components/dataset/dataset-tabs.component.ts b/client/src/app/instance/search/components/dataset/dataset-tabs.component.ts
index 2ce71fe794b347591a79c82e510026b4d191b56d..b2b87327285b93c0e8e5b9eb57bfaecd18c6ede0 100644
--- a/client/src/app/instance/search/components/dataset/dataset-tabs.component.ts
+++ b/client/src/app/instance/search/components/dataset/dataset-tabs.component.ts
@@ -7,7 +7,7 @@
  * file that was distributed with this source code.
  */
 
-import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
+import { Component, Input, ChangeDetectionStrategy, Output, EventEmitter } from '@angular/core';
 
 import { Survey, Dataset, DatasetFamily } from 'src/app/metamodel/models';
 
diff --git a/client/src/app/instance/search/containers/abstract-search.component.ts b/client/src/app/instance/search/containers/abstract-search.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8256337e9bbd279437308e3e8b3b41f292bc52ef
--- /dev/null
+++ b/client/src/app/instance/search/containers/abstract-search.component.ts
@@ -0,0 +1,85 @@
+import { Directive, OnInit, OnDestroy } from '@angular/core';
+
+import { Store } from '@ngrx/store';
+import { Observable, Subscription } from 'rxjs';
+
+import { Criterion, SearchQueryParams } from '../../store/models';
+import { Dataset, Attribute, CriteriaFamily, OutputFamily, OutputCategory } from 'src/app/metamodel/models';
+
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
+import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector';
+import * as criteriaFamilySelector from 'src/app/metamodel/selectors/criteria-family.selector';
+import * as outputFamilySelector from 'src/app/metamodel/selectors/output-family.selector';
+import * as outputCategorySelector from 'src/app/metamodel/selectors/output-category.selector';
+import * as searchActions from '../../store/actions/search.actions';
+import * as searchSelector from '../../store/selectors/search.selector';
+
+@Directive()
+export abstract class AbstractSearchComponent implements OnInit, OnDestroy {
+    public datasetSelected: Observable<string>;
+    public instanceSelected: Observable<string>;
+    public datasetListIsLoading: Observable<boolean>;
+    public datasetListIsLoaded: Observable<boolean>;
+    public datasetList: Observable<Dataset[]>;
+    public attributeList: Observable<Attribute[]>;
+    public attributeListIsLoading: Observable<boolean>;
+    public attributeListIsLoaded: Observable<boolean>;
+    public criteriaFamilyList: Observable<CriteriaFamily[]>;
+    public criteriaFamilyListIsLoading: Observable<boolean>;
+    public criteriaFamilyListIsLoaded: Observable<boolean>;
+    public outputFamilyList: Observable<OutputFamily[]>;
+    public outputFamilyListIsLoading: Observable<boolean>;
+    public outputFamilyListIsLoaded: Observable<boolean>;
+    public outputCategoryList: Observable<OutputCategory[]>;
+    public outputCategoryListIsLoading: Observable<boolean>;
+    public outputCategoryListIsLoaded: Observable<boolean>;
+    public pristine: Observable<boolean>;
+    public currentStep: Observable<string>;
+    public criteriaList: Observable<Criterion[]>;
+    public outputList: Observable<number[]>;
+    public queryParams: Observable<SearchQueryParams>;
+
+    private attributeListIsLoadedSubscription: Subscription;
+
+    constructor(protected store: Store<{ }>) {
+        this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute);
+        this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute);
+        this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading);
+        this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded);
+        this.datasetList = store.select(datasetSelector.selectAllDatasets);
+        this.attributeList = store.select(attributeSelector.selectAllAttributes);
+        this.attributeListIsLoading = store.select(attributeSelector.selectAttributeListIsLoading);
+        this.attributeListIsLoaded = store.select(attributeSelector.selectAttributeListIsLoaded);
+        this.criteriaFamilyList = store.select(criteriaFamilySelector.selectAllCriteriaFamilies);
+        this.criteriaFamilyListIsLoading = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoading);
+        this.criteriaFamilyListIsLoaded = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoaded);
+        this.outputFamilyList = store.select(outputFamilySelector.selectAllOutputFamilies);
+        this.outputFamilyListIsLoading = store.select(outputFamilySelector.selectOutputFamilyListIsLoading);
+        this.outputFamilyListIsLoaded = store.select(outputFamilySelector.selectOutputFamilyListIsLoaded);
+        this.outputCategoryList = store.select(outputCategorySelector.selectAllOutputCategories);
+        this.outputCategoryListIsLoading = store.select(outputCategorySelector.selectOutputCategoryListIsLoading);
+        this.outputCategoryListIsLoaded = store.select(outputCategorySelector.selectOutputCategoryListIsLoaded);
+        this.pristine = this.store.select(searchSelector.selectPristine);
+        this.currentStep = this.store.select(searchSelector.selectCurrentStep);
+        this.criteriaList = this.store.select(searchSelector.selectCriteriaList);
+        this.outputList = this.store.select(searchSelector.selectOutputList);
+        this.queryParams = this.store.select(searchSelector.selectQueryParams);
+    }
+
+    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(searchActions.initSearch()));
+        this.attributeListIsLoadedSubscription = this.attributeListIsLoaded.subscribe(attributeListIsLoaded => {
+            if (attributeListIsLoaded) {
+                this.store.dispatch(searchActions.loadDefaultOutputList());
+                this.store.dispatch(searchActions.loadDefaultCriteriaList());
+            }
+        });
+    }
+
+    ngOnDestroy() {
+        this.attributeListIsLoadedSubscription.unsubscribe();
+    }
+}
diff --git a/client/src/app/instance/search/containers/criteria.component.ts b/client/src/app/instance/search/containers/criteria.component.ts
index 4bc182eb0a249ee13bcda30ab3d89b90f6bf0da6..a226c24ed0131bc8d5bfba3dc12a8f590121fd29 100644
--- a/client/src/app/instance/search/containers/criteria.component.ts
+++ b/client/src/app/instance/search/containers/criteria.component.ts
@@ -7,26 +7,11 @@
  * file that was distributed with this source code.
  */
 
-import { Component, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
 
-import { Store } from '@ngrx/store';
-import { Observable } from 'rxjs';
-
-import { Criterion, SearchQueryParams } from '../../store/models';
-import { Dataset, CriteriaFamily, OutputFamily, Attribute, OutputCategory } from 'src/app/metamodel/models';
-import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
-import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
-import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
-import * as attributeActions from 'src/app/metamodel/actions/attribute.actions';
-import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector';
-import * as criteriaFamilyActions from 'src/app/metamodel/actions/criteria-family.actions';
-import * as criteriaFamilySelector from 'src/app/metamodel/selectors/criteria-family.selector';
-import * as outputFamilyActions from 'src/app/metamodel/actions/output-family.actions';
-import * as outputFamilySelector from 'src/app/metamodel/selectors/output-family.selector';
-import * as outputCategoryActions from 'src/app/metamodel/actions/output-category.actions';
-import * as outputCategorySelector from 'src/app/metamodel/selectors/output-category.selector';
+import { AbstractSearchComponent } from './abstract-search.component';
+import { Criterion } from '../../store/models';
 import * as searchActions from '../../store/actions/search.actions';
-import * as searchSelector from '../../store/selectors/search.selector';
 
 @Component({
     selector: 'app-criteria',
@@ -35,71 +20,12 @@ import * as searchSelector from '../../store/selectors/search.selector';
 /**
  * @class
  * @classdesc Search criteria container.
- *
- * @implements OnInit
  */
-export class CriteriaComponent implements OnInit {
-    public datasetSelected: Observable<string>;
-    public instanceSelected: Observable<string>;
-    public datasetListIsLoading: Observable<boolean>;
-    public datasetListIsLoaded: Observable<boolean>;
-    public datasetList: Observable<Dataset[]>;
-    public attributeList: Observable<Attribute[]>;
-    public attributeListIsLoading: Observable<boolean>;
-    public attributeListIsLoaded: Observable<boolean>;
-    public criteriaFamilyList: Observable<CriteriaFamily[]>;
-    public criteriaFamilyListIsLoading: Observable<boolean>;
-    public criteriaFamilyListIsLoaded: Observable<boolean>;
-    public outputFamilyList: Observable<OutputFamily[]>;
-    public outputFamilyListIsLoading: Observable<boolean>;
-    public outputFamilyListIsLoaded: Observable<boolean>;
-    public outputCategoryList: Observable<OutputCategory[]>;
-    public outputCategoryListIsLoading: Observable<boolean>;
-    public outputCategoryListIsLoaded: Observable<boolean>;
-    public currentStep: Observable<string>;
-    public criteriaList: Observable<Criterion[]>;
-    public outputList: Observable<number[]>;
-    public queryParams: Observable<SearchQueryParams>;
-
-    constructor(private store: Store<{ }>) {
-        this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute);
-        this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute);
-        this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading);
-        this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded);
-        this.datasetList = store.select(datasetSelector.selectAllDatasets);
-        this.attributeList = store.select(attributeSelector.selectAllAttributes);
-        this.attributeListIsLoading = store.select(attributeSelector.selectAttributeListIsLoading);
-        this.attributeListIsLoaded = store.select(attributeSelector.selectAttributeListIsLoaded);
-        this.criteriaFamilyList = store.select(criteriaFamilySelector.selectAllCriteriaFamilies);
-        this.criteriaFamilyListIsLoading = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoading);
-        this.criteriaFamilyListIsLoaded = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoaded);
-        this.outputFamilyList = store.select(outputFamilySelector.selectAllOutputFamilies);
-        this.outputFamilyListIsLoading = store.select(outputFamilySelector.selectOutputFamilyListIsLoading);
-        this.outputFamilyListIsLoaded = store.select(outputFamilySelector.selectOutputFamilyListIsLoaded);
-        this.outputCategoryList = store.select(outputCategorySelector.selectAllOutputCategories);
-        this.outputCategoryListIsLoading = store.select(outputCategorySelector.selectOutputCategoryListIsLoading);
-        this.outputCategoryListIsLoaded = store.select(outputCategorySelector.selectOutputCategoryListIsLoaded);
-        this.currentStep = this.store.select(searchSelector.selectCurrentStep);
-        this.criteriaList = this.store.select(searchSelector.selectCriteriaList);
-        this.outputList = this.store.select(searchSelector.selectOutputList);
-        this.queryParams = this.store.select(searchSelector.selectQueryParams);
-    }
-
+export class CriteriaComponent extends AbstractSearchComponent {
     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(searchActions.changeStep({ step: 'criteria' })));
         Promise.resolve(null).then(() => this.store.dispatch(searchActions.checkCriteria()));
-
-        this.store.dispatch(datasetActions.loadDatasetList());
-        this.datasetSelected.subscribe(dname => {
-            if (dname) {
-                this.store.dispatch(attributeActions.loadAttributeList());
-                this.store.dispatch(criteriaFamilyActions.loadCriteriaFamilyList());
-                this.store.dispatch(outputFamilyActions.loadOutputFamilyList());
-                this.store.dispatch(outputCategoryActions.loadOutputCategoryList());
-            }
-        });
+        super.ngOnInit();
     }
 
     /**
diff --git a/client/src/app/instance/search/containers/dataset.component.html b/client/src/app/instance/search/containers/dataset.component.html
index 53d7479f06bef4dab3df46843812d639e7981dd1..b86d581556b64900a383598f8beae670d3dff20f 100644
--- a/client/src/app/instance/search/containers/dataset.component.html
+++ b/client/src/app/instance/search/containers/dataset.component.html
@@ -26,7 +26,7 @@
         </div>
         <div class="col-12 col-md-4 col-lg-3 pt-2">
             <app-spinner *ngIf="(attributeListIsLoading | async) || (criteriaFamilyListIsLoading | async) || (outputFamilyListIsLoading | async) || (outputCategoryListIsLoading | async)"></app-spinner>
-            <app-summary *ngIf="(attributeListIsLoaded | async) && (criteriaFamilyListIsLoaded | async) && (outputFamilyListIsLoaded | async) && (outputCategoryListIsLoaded | async)"
+            <app-summary *ngIf="!(pristine | async) && (attributeListIsLoaded | async) && (criteriaFamilyListIsLoaded | async) && (outputFamilyListIsLoaded | async) && (outputCategoryListIsLoaded | async)"
                 [currentStep]="currentStep | async"
                 [datasetSelected]="datasetSelected | async"
                 [datasetList]="datasetList | async"
diff --git a/client/src/app/instance/search/containers/dataset.component.ts b/client/src/app/instance/search/containers/dataset.component.ts
index b839b48af1c93ca9f2454956fc2ea3d1d753547e..bff120abb809e855b406321d5fe87d1c4d2ddd0b 100644
--- a/client/src/app/instance/search/containers/dataset.component.ts
+++ b/client/src/app/instance/search/containers/dataset.component.ts
@@ -7,31 +7,17 @@
  * file that was distributed with this source code.
  */
 
-import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Component} from '@angular/core';
 
 import { Store } from '@ngrx/store';
-import { Observable, Subscription } from 'rxjs';
+import { Observable } from 'rxjs';
 
-import { Criterion, SearchQueryParams } from '../../store/models';
-import { Survey, Dataset, Attribute, DatasetFamily, CriteriaFamily, OutputFamily, OutputCategory } from 'src/app/metamodel/models';
+import { AbstractSearchComponent } from './abstract-search.component';
+import { Survey, DatasetFamily } from 'src/app/metamodel/models';
+import * as searchActions from '../../store/actions/search.actions';
 import * as authSelector from 'src/app/auth/auth.selector';
-import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
-import * as datasetFamilyActions from 'src/app/metamodel/actions/dataset-family.actions';
 import * as datasetFamilySelector from 'src/app/metamodel/selectors/dataset-family.selector';
-import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
-import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
-import * as surveyActions from 'src/app/metamodel/actions/survey.actions';
 import * as surveySelector from 'src/app/metamodel/selectors/survey.selector';
-import * as attributeActions from 'src/app/metamodel/actions/attribute.actions';
-import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector';
-import * as criteriaFamilyActions from 'src/app/metamodel/actions/criteria-family.actions';
-import * as criteriaFamilySelector from 'src/app/metamodel/selectors/criteria-family.selector';
-import * as outputFamilyActions from 'src/app/metamodel/actions/output-family.actions';
-import * as outputFamilySelector from 'src/app/metamodel/selectors/output-family.selector';
-import * as outputCategoryActions from 'src/app/metamodel/actions/output-category.actions';
-import * as outputCategorySelector from 'src/app/metamodel/selectors/output-category.selector';
-import * as searchActions from '../../store/actions/search.actions';
-import * as searchSelector from '../../store/selectors/search.selector';
 
 @Component({
     selector: 'app-dataset',
@@ -40,135 +26,29 @@ import * as searchSelector from '../../store/selectors/search.selector';
 /**
  * @class
  * @classdesc Search dataset container.
- *
- * @implements OnInit
  */
-export class DatasetComponent implements OnInit, OnDestroy {
+export class DatasetComponent extends AbstractSearchComponent {
     public isAuthenticated: Observable<boolean>;
-    public datasetSelected: Observable<string>;
-    public instanceSelected: Observable<string>;
     public datasetFamilyListIsLoading: Observable<boolean>;
     public datasetFamilyListIsLoaded: Observable<boolean>;
     public datasetFamilyList: Observable<DatasetFamily[]>;
-    public datasetListIsLoading: Observable<boolean>;
-    public datasetListIsLoaded: Observable<boolean>;
-    public datasetList: Observable<Dataset[]>;
     public surveyListIsLoading: Observable<boolean>;
     public surveyListIsLoaded: Observable<boolean>;
     public surveyList: Observable<Survey[]>;
-    public attributeList: Observable<Attribute[]>;
-    public attributeListIsLoading: Observable<boolean>;
-    public attributeListIsLoaded: Observable<boolean>;
-    public criteriaFamilyList: Observable<CriteriaFamily[]>;
-    public criteriaFamilyListIsLoading: Observable<boolean>;
-    public criteriaFamilyListIsLoaded: Observable<boolean>;
-    public outputFamilyList: Observable<OutputFamily[]>;
-    public outputFamilyListIsLoading: Observable<boolean>;
-    public outputFamilyListIsLoaded: Observable<boolean>;
-    public outputCategoryList: Observable<OutputCategory[]>;
-    public outputCategoryListIsLoading: Observable<boolean>;
-    public outputCategoryListIsLoaded: Observable<boolean>;
-    public currentStep: Observable<string>;
-    public criteriaList: Observable<Criterion[]>;
-    public outputList: Observable<number[]>;
-    public queryParams: Observable<SearchQueryParams>;
 
-    datasetSelectedSubscription: Subscription;
-    attributeListSubscription: Subscription;
-
-    constructor(private store: Store<{ }>) {
+    constructor(protected store: Store<{ }>) {
+        super(store);
         this.isAuthenticated = store.select(authSelector.selectIsAuthenticated);
-        this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute);
-        this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute);
         this.datasetFamilyListIsLoading = store.select(datasetFamilySelector.selectDatasetFamilyListIsLoading);
         this.datasetFamilyListIsLoaded = store.select(datasetFamilySelector.selectDatasetFamilyListIsLoaded);
         this.datasetFamilyList = store.select(datasetFamilySelector.selectAllDatasetFamilies);
-        this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading);
-        this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded);
-        this.datasetList = store.select(datasetSelector.selectAllDatasets);
         this.surveyListIsLoading = store.select(surveySelector.selectSurveyListIsLoading);
         this.surveyListIsLoaded = store.select(surveySelector.selectSurveyListIsLoaded);
         this.surveyList = store.select(surveySelector.selectAllSurveys);
-        this.attributeList = store.select(attributeSelector.selectAllAttributes);
-        this.attributeListIsLoading = store.select(attributeSelector.selectAttributeListIsLoading);
-        this.attributeListIsLoaded = store.select(attributeSelector.selectAttributeListIsLoaded);
-        this.criteriaFamilyList = store.select(criteriaFamilySelector.selectAllCriteriaFamilies);
-        this.criteriaFamilyListIsLoading = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoading);
-        this.criteriaFamilyListIsLoaded = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoaded);
-        this.outputFamilyList = store.select(outputFamilySelector.selectAllOutputFamilies);
-        this.outputFamilyListIsLoading = store.select(outputFamilySelector.selectOutputFamilyListIsLoading);
-        this.outputFamilyListIsLoaded = store.select(outputFamilySelector.selectOutputFamilyListIsLoaded);
-        this.outputCategoryList = store.select(outputCategorySelector.selectAllOutputCategories);
-        this.outputCategoryListIsLoading = store.select(outputCategorySelector.selectOutputCategoryListIsLoading);
-        this.outputCategoryListIsLoaded = store.select(outputCategorySelector.selectOutputCategoryListIsLoaded);
-        this.currentStep = this.store.select(searchSelector.selectCurrentStep);
-        this.criteriaList = this.store.select(searchSelector.selectCriteriaList);
-        this.outputList = this.store.select(searchSelector.selectOutputList);
-        this.queryParams = this.store.select(searchSelector.selectQueryParams);
     }
 
     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(searchActions.changeStep({ step: 'dataset' })));
-
-        this.store.dispatch(datasetFamilyActions.loadDatasetFamilyList());
-        this.store.dispatch(datasetActions.loadDatasetList());
-        this.store.dispatch(surveyActions.loadSurveyList());
-        this.datasetSelectedSubscription = this.datasetSelected.subscribe(dname => {
-            if (dname) {
-                this.store.dispatch(attributeActions.loadAttributeList());
-                this.store.dispatch(criteriaFamilyActions.loadCriteriaFamilyList());
-                this.store.dispatch(outputFamilyActions.loadOutputFamilyList());
-                this.store.dispatch(outputCategoryActions.loadOutputCategoryList());
-            }
-        });
-
-        this.attributeListSubscription = this.attributeList.subscribe(attributeList => {
-            if (attributeList) {
-                // Generate outputList
-                const defaultOutputList = attributeList
-                    .filter(attribute => attribute.selected && attribute.id_output_category)
-                    .map(attribute => attribute.id);
-                this.store.dispatch(searchActions.updateOutputList({ outputList: defaultOutputList }));
-
-                // Generate criteriaList
-                const defaultCriteriaList = attributeList
-                    .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;
-                        }
-                    });
-                this.store.dispatch(searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }));
-            }
-        });
-    }
-
-    ngOnDestroy() {
-        this.datasetSelectedSubscription.unsubscribe();
-        this.attributeListSubscription.unsubscribe();
+        super.ngOnInit();
     }
 }
diff --git a/client/src/app/instance/search/containers/output.component.ts b/client/src/app/instance/search/containers/output.component.ts
index 69404cdfb1294888f24b77b794dc4da39d172716..2a8962bc5c4cc6368d2cf1621ffe32a334efa560 100644
--- a/client/src/app/instance/search/containers/output.component.ts
+++ b/client/src/app/instance/search/containers/output.component.ts
@@ -7,26 +7,10 @@
  * file that was distributed with this source code.
  */
 
-import { Component, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
 
-import { Store } from '@ngrx/store';
-import { Observable } from 'rxjs';
-
-import { Criterion, SearchQueryParams } from '../../store/models';
-import { Dataset, CriteriaFamily, OutputFamily, Attribute, OutputCategory } from 'src/app/metamodel/models';
-import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
-import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
-import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
-import * as attributeActions from 'src/app/metamodel/actions/attribute.actions';
-import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector';
-import * as criteriaFamilyActions from 'src/app/metamodel/actions/criteria-family.actions';
-import * as criteriaFamilySelector from 'src/app/metamodel/selectors/criteria-family.selector';
-import * as outputFamilyActions from 'src/app/metamodel/actions/output-family.actions';
-import * as outputFamilySelector from 'src/app/metamodel/selectors/output-family.selector';
-import * as outputCategoryActions from 'src/app/metamodel/actions/output-category.actions';
-import * as outputCategorySelector from 'src/app/metamodel/selectors/output-category.selector';
+import { AbstractSearchComponent } from './abstract-search.component';
 import * as searchActions from '../../store/actions/search.actions';
-import * as searchSelector from '../../store/selectors/search.selector';
 
 @Component({
     selector: 'app-output',
@@ -35,71 +19,12 @@ import * as searchSelector from '../../store/selectors/search.selector';
 /**
  * @class
  * @classdesc Search output container.
- *
- * @implements OnInit
  */
-export class OutputComponent implements OnInit {
-    public datasetSelected: Observable<string>;
-    public instanceSelected: Observable<string>;
-    public datasetListIsLoading: Observable<boolean>;
-    public datasetListIsLoaded: Observable<boolean>;
-    public datasetList: Observable<Dataset[]>;
-    public attributeList: Observable<Attribute[]>;
-    public attributeListIsLoading: Observable<boolean>;
-    public attributeListIsLoaded: Observable<boolean>;
-    public criteriaFamilyList: Observable<CriteriaFamily[]>;
-    public criteriaFamilyListIsLoading: Observable<boolean>;
-    public criteriaFamilyListIsLoaded: Observable<boolean>;
-    public outputFamilyList: Observable<OutputFamily[]>;
-    public outputFamilyListIsLoading: Observable<boolean>;
-    public outputFamilyListIsLoaded: Observable<boolean>;
-    public outputCategoryList: Observable<OutputCategory[]>;
-    public outputCategoryListIsLoading: Observable<boolean>;
-    public outputCategoryListIsLoaded: Observable<boolean>;
-    public currentStep: Observable<string>;
-    public criteriaList: Observable<Criterion[]>;
-    public outputList: Observable<number[]>;
-    public queryParams: Observable<SearchQueryParams>;
-
-    constructor(private store: Store<{ }>) {
-        this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute);
-        this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute);
-        this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading);
-        this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded);
-        this.datasetList = store.select(datasetSelector.selectAllDatasets);
-        this.attributeList = store.select(attributeSelector.selectAllAttributes);
-        this.attributeListIsLoading = store.select(attributeSelector.selectAttributeListIsLoading);
-        this.attributeListIsLoaded = store.select(attributeSelector.selectAttributeListIsLoaded);
-        this.criteriaFamilyList = store.select(criteriaFamilySelector.selectAllCriteriaFamilies);
-        this.criteriaFamilyListIsLoading = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoading);
-        this.criteriaFamilyListIsLoaded = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoaded);
-        this.outputFamilyList = store.select(outputFamilySelector.selectAllOutputFamilies);
-        this.outputFamilyListIsLoading = store.select(outputFamilySelector.selectOutputFamilyListIsLoading);
-        this.outputFamilyListIsLoaded = store.select(outputFamilySelector.selectOutputFamilyListIsLoaded);
-        this.outputCategoryList = store.select(outputCategorySelector.selectAllOutputCategories);
-        this.outputCategoryListIsLoading = store.select(outputCategorySelector.selectOutputCategoryListIsLoading);
-        this.outputCategoryListIsLoaded = store.select(outputCategorySelector.selectOutputCategoryListIsLoaded);
-        this.currentStep = this.store.select(searchSelector.selectCurrentStep);
-        this.criteriaList = this.store.select(searchSelector.selectCriteriaList);
-        this.outputList = this.store.select(searchSelector.selectOutputList);
-        this.queryParams = this.store.select(searchSelector.selectQueryParams);
-    }
-
+export class OutputComponent extends AbstractSearchComponent {
     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(searchActions.changeStep({ step: 'output' })));
         Promise.resolve(null).then(() => this.store.dispatch(searchActions.checkOutput()));
-
-        this.store.dispatch(datasetActions.loadDatasetList());
-        this.datasetSelected.subscribe(dname => {
-            if (dname) {
-                this.store.dispatch(attributeActions.loadAttributeList());
-                this.store.dispatch(criteriaFamilyActions.loadCriteriaFamilyList());
-                this.store.dispatch(outputFamilyActions.loadOutputFamilyList());
-                this.store.dispatch(outputCategoryActions.loadOutputCategoryList());
-            }
-        });
+        super.ngOnInit();
     }
 
     /**
diff --git a/client/src/app/instance/search/containers/result.component.ts b/client/src/app/instance/search/containers/result.component.ts
index a947959e8e54ae48d836359704f3f0409df2981e..0b94c8b510b4d74951cc5425cdd5f158e7f8a795 100644
--- a/client/src/app/instance/search/containers/result.component.ts
+++ b/client/src/app/instance/search/containers/result.component.ts
@@ -12,19 +12,8 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
 
-import { Criterion, SearchQueryParams, Pagination } from '../../store/models';
-import { Dataset, CriteriaFamily, OutputFamily, Attribute, OutputCategory } from 'src/app/metamodel/models';
-import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
-import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
-import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
-import * as attributeActions from 'src/app/metamodel/actions/attribute.actions';
-import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector';
-import * as criteriaFamilyActions from 'src/app/metamodel/actions/criteria-family.actions';
-import * as criteriaFamilySelector from 'src/app/metamodel/selectors/criteria-family.selector';
-import * as outputFamilyActions from 'src/app/metamodel/actions/output-family.actions';
-import * as outputFamilySelector from 'src/app/metamodel/selectors/output-family.selector';
-import * as outputCategoryActions from 'src/app/metamodel/actions/output-category.actions';
-import * as outputCategorySelector from 'src/app/metamodel/selectors/output-category.selector';
+import { AbstractSearchComponent } from './abstract-search.component';
+import { Pagination } from '../../store/models';
 import * as searchActions from '../../store/actions/search.actions';
 import * as searchSelector from '../../store/selectors/search.selector';
 import * as sampActions from '../../store/actions/samp.actions';
@@ -41,55 +30,14 @@ import * as sampSelector from '../../store/selectors/samp.selector';
  * @implements OnInit
  * @implements OnDestroy
  */
-export class ResultComponent implements OnInit, OnDestroy {
-    public datasetSelected: Observable<string>;
-    public instanceSelected: Observable<string>;
-    public datasetListIsLoading: Observable<boolean>;
-    public datasetListIsLoaded: Observable<boolean>;
-    public datasetList: Observable<Dataset[]>;
-    public attributeList: Observable<Attribute[]>;
-    public attributeListIsLoading: Observable<boolean>;
-    public attributeListIsLoaded: Observable<boolean>;
-    public criteriaFamilyList: Observable<CriteriaFamily[]>;
-    public criteriaFamilyListIsLoading: Observable<boolean>;
-    public criteriaFamilyListIsLoaded: Observable<boolean>;
-    public outputFamilyList: Observable<OutputFamily[]>;
-    public outputFamilyListIsLoading: Observable<boolean>;
-    public outputFamilyListIsLoaded: Observable<boolean>;
-    public outputCategoryList: Observable<OutputCategory[]>;
-    public outputCategoryListIsLoading: Observable<boolean>;
-    public outputCategoryListIsLoaded: Observable<boolean>;
-    public currentStep: Observable<string>;
-    public criteriaList: Observable<Criterion[]>;
-    public outputList: Observable<number[]>;
-    public queryParams: Observable<SearchQueryParams>;
+export class ResultComponent extends AbstractSearchComponent {
     public dataLength: Observable<number>;
     public dataLengthIsLoading: Observable<boolean>;
     public dataLengthIsLoaded: Observable<boolean>;
     public sampRegistered: Observable<boolean>;
 
-    constructor(private store: Store<{ }>) {
-        this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute);
-        this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute);
-        this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading);
-        this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded);
-        this.datasetList = store.select(datasetSelector.selectAllDatasets);
-        this.attributeList = store.select(attributeSelector.selectAllAttributes);
-        this.attributeListIsLoading = store.select(attributeSelector.selectAttributeListIsLoading);
-        this.attributeListIsLoaded = store.select(attributeSelector.selectAttributeListIsLoaded);
-        this.criteriaFamilyList = store.select(criteriaFamilySelector.selectAllCriteriaFamilies);
-        this.criteriaFamilyListIsLoading = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoading);
-        this.criteriaFamilyListIsLoaded = store.select(criteriaFamilySelector.selectCriteriaFamilyListIsLoaded);
-        this.outputFamilyList = store.select(outputFamilySelector.selectAllOutputFamilies);
-        this.outputFamilyListIsLoading = store.select(outputFamilySelector.selectOutputFamilyListIsLoading);
-        this.outputFamilyListIsLoaded = store.select(outputFamilySelector.selectOutputFamilyListIsLoaded);
-        this.outputCategoryList = store.select(outputCategorySelector.selectAllOutputCategories);
-        this.outputCategoryListIsLoading = store.select(outputCategorySelector.selectOutputCategoryListIsLoading);
-        this.outputCategoryListIsLoaded = store.select(outputCategorySelector.selectOutputCategoryListIsLoaded);
-        this.currentStep = this.store.select(searchSelector.selectCurrentStep);
-        this.criteriaList = this.store.select(searchSelector.selectCriteriaList);
-        this.outputList = this.store.select(searchSelector.selectOutputList);
-        this.queryParams = this.store.select(searchSelector.selectQueryParams);
+    constructor(protected store: Store<{ }>) {
+        super(store);
         this.dataLength = this.store.select(searchSelector.selectDataLength);
         this.dataLengthIsLoading = this.store.select(searchSelector.selectDataLengthIsLoading);
         this.dataLengthIsLoaded = this.store.select(searchSelector.selectDataLengthIsLoaded);
@@ -101,16 +49,7 @@ export class ResultComponent implements OnInit, OnDestroy {
         // This micro task prevent the expression has changed after view init error
         Promise.resolve(null).then(() => this.store.dispatch(searchActions.changeStep({ step: 'result' })));
         Promise.resolve(null).then(() => this.store.dispatch(searchActions.checkResult()));
-
-        this.store.dispatch(datasetActions.loadDatasetList());
-        this.datasetSelected.subscribe(dname => {
-            if (dname) {
-                this.store.dispatch(attributeActions.loadAttributeList());
-                this.store.dispatch(criteriaFamilyActions.loadCriteriaFamilyList());
-                this.store.dispatch(outputFamilyActions.loadOutputFamilyList());
-                this.store.dispatch(outputCategoryActions.loadOutputCategoryList());
-            }
-        });
+        super.ngOnInit();
     }
 
     sampRegister() {
@@ -164,5 +103,6 @@ export class ResultComponent implements OnInit, OnDestroy {
      */
     ngOnDestroy() {
         this.store.dispatch(searchActions.destroyResults());
+        super.ngOnDestroy();
     }
 }
diff --git a/client/src/app/instance/search/search.component.ts b/client/src/app/instance/search/search.component.ts
index ac08afa731ed6b5ac6a14bf0675420d894e96d58..175c4e9bd1d0e714fabdfeff01e4f4491ac3beac 100644
--- a/client/src/app/instance/search/search.component.ts
+++ b/client/src/app/instance/search/search.component.ts
@@ -44,7 +44,5 @@ export class SearchComponent {
         this.resultStepChecked = store.select(searchSelector.selectResultStepChecked);
         this.queryParams = this.store.select(searchSelector.selectQueryParams);
         this.outputList = this.store.select(searchSelector.selectOutputList);
-        // this.store.dispatch(new searchMultipleActions.ResetSearchAction());
-        // this.store.dispatch(new coneSearchActions.DeleteConeSearchAction());
     }
 }
diff --git a/client/src/app/instance/store/actions/metamodel.actions.ts b/client/src/app/instance/store/actions/metamodel.actions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e7e7638b53b2dc3b2d50db79d4c6b445ae27daf3
--- /dev/null
+++ b/client/src/app/instance/store/actions/metamodel.actions.ts
@@ -0,0 +1,13 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { createAction, props } from '@ngrx/store';
+
+export const loadInstanceMetamodel = createAction('[Metamodel] Load Instance Metamodel');
+export const changeCurrentInstance = createAction('[Metamodel] Change Current Instance', props<{ currentInstance: string }>());
diff --git a/client/src/app/instance/store/actions/search.actions.ts b/client/src/app/instance/store/actions/search.actions.ts
index e8ff7dd30ad84b885a7753cd2f2cb0e466139fbe..d180d538d9aa427336b6e0038a119ef92a904505 100644
--- a/client/src/app/instance/store/actions/search.actions.ts
+++ b/client/src/app/instance/store/actions/search.actions.ts
@@ -12,6 +12,11 @@ import { createAction, props } from '@ngrx/store';
 import { Criterion, Pagination } from '../models';
 
 export const initSearch = createAction('[Search] Init Search');
+export const restartSearch = createAction('[Search] Restart Search');
+export const loadDefaultCriteriaList = createAction('[Search] Load Default Criteria List');
+export const loadDefaultOutputList = createAction('[Search] Load Default Output List');
+export const markAsDirty = createAction('[Search] Mark As Dirty');
+export const changeCurrentDataset = createAction('[Search] Change Current Dataset', props<{ currentDataset: string }>());
 export const changeStep = createAction('[Search] Change Step', props<{ step: string }>());
 export const checkCriteria = createAction('[Search] Check Criteria');
 export const checkOutput = createAction('[Search] Check Output');
diff --git a/client/src/app/instance/store/effects/index.ts b/client/src/app/instance/store/effects/index.ts
index 806a9ba40b71eaa89e2da28dc57c7b446e878985..296d89b24794a19ce38357ac7eab009ed9234257 100644
--- a/client/src/app/instance/store/effects/index.ts
+++ b/client/src/app/instance/store/effects/index.ts
@@ -1,7 +1,9 @@
+import { MetamodelEffects } from './metamodel.effects';
 import { SampEffects } from "./samp.effects";
 import { SearchEffects } from "./search.effects";
 
 export const instanceEffects = [
+    MetamodelEffects,
     SampEffects,
     SearchEffects
 ];
diff --git a/client/src/app/instance/store/effects/metamodel.effects.ts b/client/src/app/instance/store/effects/metamodel.effects.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c81b9168c3a7e85105aa45f8743f139dbbcc3529
--- /dev/null
+++ b/client/src/app/instance/store/effects/metamodel.effects.ts
@@ -0,0 +1,57 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { Injectable } from '@angular/core';
+
+import { Actions, createEffect, ofType, concatLatestFrom } from '@ngrx/effects';
+import { Store } from '@ngrx/store';
+import { of } from 'rxjs';
+import { mergeMap } from 'rxjs/operators';
+
+import * as metamodelActions from '../actions/metamodel.actions';
+import * as metamodelSelector from '../selectors/metamodel.selector';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
+import * as datasetFamilyActions from 'src/app/metamodel/actions/dataset-family.actions';
+import * as surveyActions from 'src/app/metamodel/actions/survey.actions';
+
+@Injectable()
+export class MetamodelEffects {
+    loadInstanceMetamodel$ = createEffect(() =>
+        this.actions$.pipe(
+            ofType(metamodelActions.loadInstanceMetamodel),
+            concatLatestFrom(() => [
+                this.store.select(instanceSelector.selectInstanceNameByRoute),
+                this.store.select(metamodelSelector.selectCurrentInstance),
+                this.store.select(metamodelSelector.selectInstanceMetamodelIsLoaded)
+            ]),
+            mergeMap(([action, instanceName, currentInstance, instanceMetamodelIsLoaded]) => {
+                if (instanceName && instanceName !== currentInstance) {
+                    instanceMetamodelIsLoaded = false;
+                }
+
+                if (!instanceMetamodelIsLoaded) {
+                    return [
+                        metamodelActions.changeCurrentInstance({ currentInstance: instanceName }),
+                        datasetFamilyActions.loadDatasetFamilyList(),
+                        datasetActions.loadDatasetList(),
+                        surveyActions.loadSurveyList()
+                    ];
+                } else {
+                    return of({ type: '[No Action] Load Instance Metamodel' });
+                }
+            })
+        )
+    );
+
+    constructor(
+        private actions$: Actions,
+        private store: Store<{ }>
+    ) {}
+}
diff --git a/client/src/app/instance/store/effects/search.effects.ts b/client/src/app/instance/store/effects/search.effects.ts
index bd974095fcfb392476832afa2fe7af12bdb53a82..f400e805e409adbf27ce6992d780022f7d73955b 100644
--- a/client/src/app/instance/store/effects/search.effects.ts
+++ b/client/src/app/instance/store/effects/search.effects.ts
@@ -7,22 +7,187 @@
  * file that was distributed with this source code.
  */
 
- import { Injectable } from '@angular/core';
-
- import { Actions, createEffect, ofType, concatLatestFrom } from '@ngrx/effects';
- import { Store } from '@ngrx/store';
- import { of } from 'rxjs';
- import { map, tap, mergeMap, catchError } from 'rxjs/operators';
- import { ToastrService } from 'ngx-toastr';
- 
- import { getCriterionStr } from '../models';
- import { SearchService } from '../services/search.service';
- import * as searchActions from '../actions/search.actions';
- import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
- import * as searchSelector from '../selectors/search.selector';
-  
- @Injectable()
- export class SearchEffects {
+import { Injectable } from '@angular/core';
+
+import { Actions, createEffect, ofType, concatLatestFrom } from '@ngrx/effects';
+import { Store, Action  } from '@ngrx/store';
+import { of } from 'rxjs';
+import { map, tap, mergeMap, catchError } from 'rxjs/operators';
+import { ToastrService } from 'ngx-toastr';
+
+import { getCriterionStr } from '../models';
+import { SearchService } from '../services/search.service';
+import * as searchActions from '../actions/search.actions';
+import * as attributeActions from 'src/app/metamodel/actions/attribute.actions';
+import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector';
+import * as criteriaFamilyActions from 'src/app/metamodel/actions/criteria-family.actions';
+import * as outputFamilyActions from 'src/app/metamodel/actions/output-family.actions';
+import * as outputCategoryActions from 'src/app/metamodel/actions/output-category.actions';
+import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
+import * as searchSelector from '../selectors/search.selector';
+
+@Injectable()
+export class SearchEffects {
+    initSearch$ = createEffect(() =>
+        this.actions$.pipe(
+            ofType(searchActions.initSearch),
+            concatLatestFrom(() => [
+                this.store.select(datasetSelector.selectDatasetNameByRoute),
+                this.store.select(searchSelector.selectCurrentDataset),
+                this.store.select(searchSelector.selectPristine),
+                this.store.select(searchSelector.selectStepsByRoute)
+            ]),
+            mergeMap(([action, datasetName, currentDataset, pristine, steps]) => {
+                // User has changed dataset: reload initial state + init search
+                if (datasetName && currentDataset && datasetName !== currentDataset) {
+                    return of(searchActions.restartSearch());
+                }
+
+                // User has selected a dataset or page is reloaded: load dataset metamodel
+                if (datasetName && pristine) {
+                    let actions: Action[] = [
+                        searchActions.markAsDirty(),
+                        searchActions.changeCurrentDataset({ currentDataset: datasetName }),
+                        attributeActions.loadAttributeList(),
+                        criteriaFamilyActions.loadCriteriaFamilyList(),
+                        outputFamilyActions.loadOutputFamilyList(),
+                        outputCategoryActions.loadOutputCategoryList()
+                    ];
+                    if (steps) {
+                        if(steps[0] === '1') {
+                            actions.push(searchActions.checkCriteria());
+                        }
+                        if(steps[1] === '1') {
+                            actions.push(searchActions.checkOutput());
+                        }
+                        if(steps[2] === '1') {
+                            actions.push(searchActions.checkResult());
+                        }
+                    }
+                    return actions;
+                }
+
+                // User come back to the search module: reload initial state
+                if(!datasetName && !pristine) {
+                    return of(searchActions.resetSearch());
+                }
+
+                // User change step and it's the same search: No action
+                return of({ type: '[No Action] Init Search' });
+            })
+        )
+    );
+
+    restartSearch$ = createEffect(() => 
+        this.actions$.pipe(
+            ofType(searchActions.restartSearch),
+            map(() => searchActions.initSearch())
+        )
+    );
+
+    loadDefaultCriteriaList$ = createEffect(() =>
+        this.actions$.pipe(
+            ofType(searchActions.loadDefaultCriteriaList),
+            concatLatestFrom(() => [
+                this.store.select(attributeSelector.selectAllAttributes),
+                this.store.select(searchSelector.selectCriteriaListByRoute)
+            ]),
+            mergeMap(([action, attributeList, criteriaList]) => {
+                let defaultCriteriaList = [];
+                if (criteriaList) {
+                    defaultCriteriaList = criteriaList.split(';').map((c: string) => {
+                        const params = c.split('::');
+                        const attribute = attributeList.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;
+                        }
+                    });
+                } else {
+                    defaultCriteriaList = attributeList
+                        .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;
+                            }
+                        });
+                }
+                return of(searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }));
+            })
+        )
+    );
+
+    loadDefaultOutputList$ = createEffect(() =>
+        this.actions$.pipe(
+            ofType(searchActions.loadDefaultOutputList),
+            concatLatestFrom(() => [
+                this.store.select(attributeSelector.selectAllAttributes),
+                this.store.select(searchSelector.selectOutputListByRoute)
+            ]),
+            mergeMap(([action, attributeList, outputList]) => {
+                let defaultOutputList = [];
+                if (outputList) {
+                    defaultOutputList = outputList.split(';').map((o: string) => parseInt(o, 10));
+                } else {
+                    defaultOutputList = attributeList
+                        .filter(attribute => attribute.selected && attribute.id_output_category)
+                        .map(attribute => attribute.id);
+                }
+                return of(searchActions.updateOutputList({ outputList: defaultOutputList }));
+            })
+        )
+    );
+
     retrieveDataLength$ = createEffect(() =>
         this.actions$.pipe(
             ofType(searchActions.retrieveDataLength),
@@ -90,4 +255,4 @@
         private store: Store<{ }>,
         private toastr: ToastrService
     ) {}
- }
+}
diff --git a/client/src/app/instance/store/reducers/metamodel.reducer.ts b/client/src/app/instance/store/reducers/metamodel.reducer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6a1733f0d13cc44a468e27b2214beba2ce4fec0b
--- /dev/null
+++ b/client/src/app/instance/store/reducers/metamodel.reducer.ts
@@ -0,0 +1,34 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { createReducer, on } from '@ngrx/store';
+
+import * as metamodelActions from '../actions/metamodel.actions';
+
+export interface State {
+    currentInstance: string;
+    instanceMetamodelIsLoaded: boolean;
+}
+
+export const initialState: State = {
+    currentInstance: null,
+    instanceMetamodelIsLoaded: false
+}
+
+export const metamodelReducer = createReducer(
+    initialState,
+    on(metamodelActions.changeCurrentInstance, (state, { currentInstance }) => ({
+        ...state,
+        currentInstance,
+        instanceMetamodelIsLoaded: true
+    }))
+);
+
+export const selectCurrentInstance = (state: State) => state.currentInstance;
+export const selectInstanceMetamodelIsLoaded = (state: State) => state.instanceMetamodelIsLoaded;
diff --git a/client/src/app/instance/store/reducers/search.reducer.ts b/client/src/app/instance/store/reducers/search.reducer.ts
index 96608d3b3ffbae8d79c438bb69fde1dfae98b6b4..9465027947ce6346bc86cd5f5fbe56e6ea761f7b 100644
--- a/client/src/app/instance/store/reducers/search.reducer.ts
+++ b/client/src/app/instance/store/reducers/search.reducer.ts
@@ -14,6 +14,7 @@ import * as searchActions from '../actions/search.actions';
 
 export interface State {
     pristine: boolean;
+    currentDataset: string,
     currentStep: string;
     criteriaStepChecked: boolean;
     outputStepChecked: boolean;
@@ -30,6 +31,7 @@ export interface State {
 
 export const initialState: State = {
     pristine: true,
+    currentDataset: null,
     currentStep: null,
     criteriaStepChecked: false,
     outputStepChecked: false,
@@ -46,10 +48,22 @@ export const initialState: State = {
 
 export const searchReducer = createReducer(
     initialState,
+    on(searchActions.restartSearch, () => ({
+        ...initialState,
+        currentStep: 'dataset'
+    })),
     on(searchActions.changeStep, (state, { step }) => ({
         ...state,
         currentStep: step
     })),
+    on(searchActions.markAsDirty, state => ({
+        ...state,
+        pristine: false
+    })),
+    on(searchActions.changeCurrentDataset, (state, { currentDataset }) => ({
+        ...state,
+        currentDataset
+    })),
     on(searchActions.checkCriteria, state => ({
         ...state,
         criteriaStepChecked: true
@@ -97,6 +111,7 @@ export const searchReducer = createReducer(
 );
 
 export const selectPristine = (state: State) => state.pristine;
+export const selectCurrentDataset = (state: State) => state.currentDataset;
 export const selectCurrentStep = (state: State) => state.currentStep;
 export const selectCriteriaStepChecked = (state: State) => state.criteriaStepChecked;
 export const selectOutputStepChecked = (state: State) => state.outputStepChecked;
diff --git a/client/src/app/instance/store/selectors/metamodel.selector.ts b/client/src/app/instance/store/selectors/metamodel.selector.ts
new file mode 100644
index 0000000000000000000000000000000000000000..31195a6039dff02158ef4a9052c45d50dffd74cd
--- /dev/null
+++ b/client/src/app/instance/store/selectors/metamodel.selector.ts
@@ -0,0 +1,28 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { createSelector } from '@ngrx/store';
+
+import * as reducer from '../../instance.reducer';
+import * as fromMetamodel from '../reducers/metamodel.reducer';
+
+export const selectMetamodelState = createSelector(
+    reducer.getInstanceState,
+    (state: reducer.State) => state.metamodel
+);
+
+export const selectCurrentInstance = createSelector(
+    selectMetamodelState,
+    fromMetamodel.selectCurrentInstance
+);
+
+export const selectInstanceMetamodelIsLoaded = createSelector(
+    selectMetamodelState,
+    fromMetamodel.selectInstanceMetamodelIsLoaded
+);
diff --git a/client/src/app/instance/store/selectors/samp.selector.ts b/client/src/app/instance/store/selectors/samp.selector.ts
index 3446fc74d5bf507e8eedfa815a1cfdfbe4e46cb1..d485b19f91a13a881a78ae04896e117a2b9dc7f5 100644
--- a/client/src/app/instance/store/selectors/samp.selector.ts
+++ b/client/src/app/instance/store/selectors/samp.selector.ts
@@ -7,11 +7,15 @@
  * file that was distributed with this source code.
  */
 
-import { createSelector, createFeatureSelector } from '@ngrx/store';
+import { createSelector } from '@ngrx/store';
 
+import * as reducer from '../../instance.reducer';
 import * as fromSamp from '../reducers/samp.reducer';
 
-export const selectSampState = createFeatureSelector<fromSamp.State>('samp');
+export const selectSampState = createSelector(
+    reducer.getInstanceState,
+    (state: reducer.State) => state.samp
+);
 
 export const selectRegistered = createSelector(
     selectSampState,
diff --git a/client/src/app/instance/store/selectors/search.selector.ts b/client/src/app/instance/store/selectors/search.selector.ts
index e7a8233c180606bd5de58a7f74fa68a50a9052d7..af427be8ddbc2b30a1bc30a07949056f16296385 100644
--- a/client/src/app/instance/store/selectors/search.selector.ts
+++ b/client/src/app/instance/store/selectors/search.selector.ts
@@ -13,73 +13,78 @@ import { Criterion, SearchQueryParams, getCriterionStr } from '../models';
 import * as reducer from '../../instance.reducer';
 import * as fromSearch from '../reducers/search.reducer';
 
-export const selectAttributeState = createSelector(
+export const selectInstanceState = createSelector(
     reducer.getInstanceState,
     (state: reducer.State) => state.search
 );
 
 export const selectPristine = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectPristine
 );
 
+export const selectCurrentDataset = createSelector(
+    selectInstanceState,
+    fromSearch.selectCurrentDataset
+);
+
 export const selectCurrentStep = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectCurrentStep
 );
 
 export const selectCriteriaStepChecked = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectCriteriaStepChecked
 );
 
 export const selectOutputStepChecked = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectOutputStepChecked
 );
 
 export const selectResultStepChecked = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectResultStepChecked
 );
 
 export const selectIsConeSearchAdded = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectIsConeSearchAdded
 );
 
 export const selectCriteriaList = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectCriteriaList
 );
 
 export const selectOutputList = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectOutputList
 );
 
 export const selectSearchData = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectSearchData
 );
 
 export const selectDataLengthIsLoading = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectDataLengthIsLoading
 );
 
 export const selectDataLengthIsLoaded = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectDataLengthIsLoaded
 );
 
 export const selectDataLength = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectDataLength
 );
 
 export const selectSelectedData = createSelector(
-    selectAttributeState,
+    selectInstanceState,
     fromSearch.selectSelectedData
 );
 
@@ -112,3 +117,18 @@ export const selectQueryParams = createSelector(
         return queryParams;
     }
 );
+
+export const selectStepsByRoute = createSelector(
+    reducer.selectRouterState,
+    router => router.state.queryParams.s as string
+);
+
+export const selectCriteriaListByRoute = createSelector(
+    reducer.selectRouterState,
+    router => router.state.queryParams.c as string
+);
+
+export const selectOutputListByRoute = createSelector(
+    reducer.selectRouterState,
+    router => router.state.queryParams.a as string
+);
diff --git a/client/src/app/metamodel/reducers/attribute.reducer.ts b/client/src/app/metamodel/reducers/attribute.reducer.ts
index 6db9742ea4d663cc80a5b74a82d261fd6bde1290..9276122e8180a0d006d9b7bdadd62bb1c3619cae 100644
--- a/client/src/app/metamodel/reducers/attribute.reducer.ts
+++ b/client/src/app/metamodel/reducers/attribute.reducer.ts
@@ -30,7 +30,8 @@ export const attributeReducer = createReducer(
     on(attributeActions.loadAttributeList, (state) => {
         return {
             ...state,
-            attributeListIsLoading: true
+            attributeListIsLoading: true,
+            attributeListIsLoaded: false
         }
     }),
     on(attributeActions.loadAttributeListSuccess, (state, { attributes }) => {