diff --git a/web/app/static/js/modules/corpus_analysis/client/Client.js b/web/app/static/js/modules/corpus_analysis/client/Client.js
index 09566c291d5369e873ef21e16429fd761cdb012d..122add1eb90e32fabe941062d47a463af1d5d473 100644
--- a/web/app/static/js/modules/corpus_analysis/client/Client.js
+++ b/web/app/static/js/modules/corpus_analysis/client/Client.js
@@ -16,7 +16,7 @@ class Client {
     this.logging = logging;
     this.requestQueryProgress = 0;
     this.socket = socket;
-    this.socketEventListeners = {};
+    this.eventListeners = {};
     this.connected = false;
 
 
@@ -44,9 +44,9 @@ class Client {
   }
 
   // Registers one or more SocketEventListeners to the Client.
-  setSocketEventListeners(socketEventListeners) {
-    for (let socketEventListener of socketEventListeners) {
-      this.socketEventListeners[socketEventListener.type] = socketEventListener;
+  setSocketEventListeners(eventListeners) {
+    for (let eventListener of eventListeners) {
+      this.eventListeners[eventListener.type] = eventListener;
     }
   }
 
@@ -55,7 +55,7 @@ class Client {
    * type strings because they double as the socket event event names.
    */
   loadSocketEventListeners() {
-    for (let [type, listener] of Object.entries(this.socketEventListeners)) {
+    for (let [type, listener] of Object.entries(this.eventListeners)) {
       listener.listenerFunction(type, this);
     }
   }
@@ -66,8 +66,8 @@ class Client {
    */
   notifyView(caseIdentifier, detailObject={}) {
     detailObject.caseIdentifier = caseIdentifier;
-    const event = new CustomEvent('notify', { detail: detailObject });
-    console.info('Dispatching Notification:', caseIdentifier);
+    const event = new CustomEvent('notify-view', { detail: detailObject });
+    console.info('Client dispatching Notification:', caseIdentifier);
     document.dispatchEvent(event);
   }
 
@@ -105,16 +105,38 @@ class Client {
                  'socket.emit for the query', queryStr);
     this.socket.emit('corpus_analysis_query', queryStr);
   }
+
+  // create results data either from all results or from all marked sub results
+  getResultsData(resultsType, dataIndexes, results) {
+    // TODO: where to put all the stuff that deactivates all the buttons because cqp server cannot handle mutliple requests?
+    // Triggers emit to get full match context from server for a number of
+    // matches identified by their data_index.
+    let tmp_first_cpos = [];
+    let tmp_last_cpos = [];
+    for (let dataIndex of dataIndexes) {
+      tmp_first_cpos.push(results.data.matches[dataIndex].c[0]);
+      tmp_last_cpos.push(results.data.matches[dataIndex].c[1]);
+    }
+    nopaque.socket.emit("corpus_analysis_inspect_match",
+                        {
+                          type: resultsType,
+                          data_indexes: dataIndexes,
+                          first_cpos: tmp_first_cpos,
+                          last_cpos: tmp_last_cpos,
+                        });
+  }
+
 }
 
+
 /**
  * This class is used to create an SocketEventListener.
  * Input are an identifying type string, the listener function and callbacks
  * which will be executed as part of the listener function. The identifying
  * type string is also used as the socket event event identifier.
  */
-class SocketEventListener {
-  constructor(type, listenerFunction, args=null) {
+class ClientEventListener {
+  constructor(type, listenerFunction) {
     this.listenerCallbacks = {};
     this.listenerFunction = listenerFunction;
     this.type = type;
@@ -127,8 +149,8 @@ class SocketEventListener {
     }
   }
 
-  /** Shorthand to execute all registered callbacks with same args in insertion
-   * order.
+  /** Shorthand to execute all registered callbacks with same defaultArgs
+   * in insertion order.
    * NOTE:
    * Since ECMAScript 2015, objects do preserve creation order for
    * string and Symbol keys. In JavaScript engines that comply with the
@@ -136,11 +158,18 @@ class SocketEventListener {
    * yield the keys in order of insertion.
    * So all modern Browsers.
    */
-  executeCallbacks(payload) {
+  executeCallbacks(defaultArgs) {
     for (let [type, listenerCallback] of Object.entries(this.listenerCallbacks)) {
-      listenerCallback.callbackFunction(payload, ...listenerCallback.args);
+      listenerCallback.callbackFunction(...defaultArgs,
+                                        ...listenerCallback.args);
     }
   }
+  // use this if you only want to execute a specific registered callback
+  executeCallback(defaultArgs, type) {
+    let listenerCallback = this.listenerCallbacks[type];
+    listenerCallback.callbackFunction(...defaultArgs,
+                                      ...listenerCallback.args);
+  }
 }
 
 /**
@@ -159,6 +188,6 @@ class ListenerCallback {
 // export Classes from this module
 export {
   Client,
-  SocketEventListener,
+  ClientEventListener,
   ListenerCallback,
 };
\ No newline at end of file
diff --git a/web/app/static/js/modules/corpus_analysis/client/callbacks.js b/web/app/static/js/modules/corpus_analysis/client/callbacks.js
index afda9fe7e315fc34fc5d91c6a0d35e259f19d245..145bdaa5a596fb39c66fa53b65368e6c1dbdcf6d 100644
--- a/web/app/static/js/modules/corpus_analysis/client/callbacks.js
+++ b/web/app/static/js/modules/corpus_analysis/client/callbacks.js
@@ -46,116 +46,24 @@ function saveQueryData(args) {
   }
 }
 
-function querySetup(payload, client) {
-  // deletes old data from query issued before this new query
-  client.results.clearAll();
-  // load necessary HTMLElements with selectory syntax and save them as fields
-  client.getHTMLElements(['#query-progress-bar', '#query-results-user-feedback',
-                          '#recieved-match-count', '#total-match-count',
-                          '#text-lookup-count', '#text-lookup-titles',
-                          '#query-results-create', '#add-to-sub-results']);
-  client.recievedMatchCount.textContent = 0;
-  client.totalMatchCount.textContent = `${payload.match_count}`;
-  client.queryResultsUserFeedback.classList.toggle('hide');
-  client.queryProgressBar.classList.toggle('hide');
-  client.queryProgressBar.lastElementChild.style.width = '0%';
-  if (client.dynamicMode) {
-    client.addToSubResults.toggleAttribute('disabled');
-    client.queryResultsCreate.classList.toggle('disabled');
-  }
-}
-
-/**
- * This callback should be registered to the SocketEventListener 'recieveQueryData'
- * It takes the incoming chunk and renders the results using the
- * results.jsList object. It can either handle live incoming data chunks or
- * already loaded/imported results data.
- */
-function queryRenderResults(payload, client) {
-  client.getHTMLElements(['#recieved-match-count', '#match-count',
-                          '#display-options-form-expert_mode']);
-  const renderResults = (data) => {
-    /**
-     * resultItem saves the incoming chunk matches as objects to add those later
-     * to the client.results.jsList
-     */
-   let resultItems = [];
-   // get infos for full match row
-   for (let [index, match] of data.matches.entries()) {
-     resultItems.push({...match, ...{'index': index + client.results.data.matches.length}});
-   }
-     client.results.jsList.add(resultItems, (items) => {
-       for (let item of items) {
-         item.elm = client.results.jsList.createResultRowElement(item, data);
-       }
-     });
-  }
-  if (client.dynamicMode) {
-    if (payload.chunk.cpos_ranges == true) {
-      client.results.data['cpos_ranges'] = true;
-    } else {
-      client.results.data['cpos_ranges'] = false;
-    }
-    renderResults(payload.chunk);
-    helperQueryRenderResults(payload, client);
-    console.info('Result progress is:', client.requestQueryProgress);
-    if (client.requestQueryProgress === 100) {
-      /**
-       * activate, hide or show elements if all reults have been recieved
-       * also load some new elements taht have not ben loaded before
-       */
-      client.queryProgressBar.classList.toggle('hide');
-      client.queryResultsUserFeedback.classList.toggle('hide');
-      client.queryResultsCreate.classList.toggle('disabled');
-      client.addToSubResults.toggleAttribute('disabled');
-    //   addToSubResultsElement.removeAttribute("disabled");
-    //   // inital expert mode check and sub results activation
-    //   client.results.jsList.activateInspect();
-    //   if (addToSubResultsElement.checked) {
-    //     client.results.jsList.activateAddToSubResults();
-    //   }
-    //   if (expertModeSwitchElement.checked) {
-    //     client.results.jsList.expertModeOn("query-display");
-    //   }
-    }
-  } else if (!client.dynamicMode) {
-    renderResults(payload);
-    helperQueryRenderResults({'chunk': payload}, client);
-    client.queryProgressBar.classList.toggle('hide');
-    client.queryResultsUserFeedback.classList.toggle('hide');
-    client.results.jsList.activateInspect();
-    if (client.displayOptionsFormExpertMode.checked) {
-      client.results.jsList.expertModeOn("query-display");
-    }
-  }
+function getResultsData(args) {
+  let [resultsType, dataIndexes, client, results, rest] = arguments;
+  client.notifyView('results-data-recieving');
+  client.getResultsData(resultsType, dataIndexes, results);
 }
 
-/**
- * Helper function that saves result data into the client.results.data object.
- * Also does some showing and hiding of Elements and user feedback text.
- */
-function helperQueryRenderResults (payload, client) {
-  // updating table on finished item creation callback via createResultRowElement
-  client.results.jsList.update();
-  client.results.jsList.changeContext(); // sets lr context on first result load
-  // incorporating new chunk results into full results
-  client.results.data.matches.push(...payload.chunk.matches);
-  client.results.data.addData(payload.chunk.cpos_lookup, 'cpos_lookup');
-  client.results.data.addData(payload.chunk.text_lookup, 'text_lookup');
-  // complete metaData
-  // client.results.metaData.add();
-  // show user current and total match count
-  client.recievedMatchCount.textContent = `${client.results.data.matches.length}`;
-  client.textLookupCount.textContent = `${Object.keys(client.results.data.text_lookup).length}`;
-  let titles = new Array();
-  for (let [key, value] of Object.entries(client.results.data.text_lookup)) {
-    titles.push(`${value.title} (${value.publishing_year})`);
-  };
-  client.textLookupTitles.textContent = `${titles.join(", ")}`;
-  // update progress bar and requestQueryProgress
-  client.queryProgressBar.lastElementChild.style.width =  `${payload.progress}%`;
-  client.requestQueryProgress = payload.progress;
+function saveResultsData(args) {
+  let [payload, client, results, rest] = arguments;
+  // code to save results data depending on type
+  console.info('Results data has been saved.');
+  client.notifyView('results-data-recieved');
 }
 
 // export callbacks
-export { prepareQueryData, saveMetaData, saveQueryData };
\ No newline at end of file
+export {
+  prepareQueryData,
+  saveMetaData,
+  saveQueryData,
+  getResultsData,
+  saveResultsData,
+};
\ No newline at end of file
diff --git a/web/app/static/js/modules/corpus_analysis/client/listeners.js b/web/app/static/js/modules/corpus_analysis/client/listeners.js
index 681bf6c657b1bbe9368ce0cbf68512c710e6495a..11bfc22bcdfcb9e49ec21b83cb34d69266ac1626 100644
--- a/web/app/static/js/modules/corpus_analysis/client/listeners.js
+++ b/web/app/static/js/modules/corpus_analysis/client/listeners.js
@@ -1,9 +1,14 @@
 /**
  * This file contains the listener functions which can be assigned to the
  * coprus_analysis client. So that the incoming data/status informations will
- * be handled.
+ * be handled. There are several listeners listening for socket .io events.
+ * Further below one javascript custom event listener is specified. This
+ * listener listens for javascript custom events which are being dispatched by
+ * the View (resultsList).
  */
 
+// Listeners for socket io events
+
 /**
  * Recieves a corpus analysis connected signal via socket.io.
  */
@@ -50,7 +55,7 @@ function recieveMetaData(type, client) {
       console.info(`corpus_analysis_meta_data: ${response.code} - ${response.msg}`);
       console.info(response);
       // executing the registered callbacks
-      client.socketEventListeners[type].executeCallbacks(response.payload);
+      client.eventListeners[type].executeCallbacks([response.payload]);
       console.groupEnd();
     } else {
       console.group('Failed to recieve meta data.');
@@ -81,7 +86,7 @@ function recieveQueryStatus(type, client) {
       console.info(`corpus_analysis_query: ${response.code} - ${response.msg}`);
       console.info(response);
       // executing the registered callbacks
-      client.socketEventListeners[type].executeCallbacks(response.payload);
+      client.eventListeners[type].executeCallbacks([response.payload]);
       console.groupEnd();
     } else {
       console.group('corpus_analysis_query: Client failed recieving',
@@ -113,7 +118,7 @@ function recieveQueryData(type, client) {
       /**
        * Execute registered callbacks and notify View.
        */
-      client.socketEventListeners[type].executeCallbacks(response.payload);
+      client.eventListeners[type].executeCallbacks([response.payload]);
       console.info('Added chunk data to results.data.');
       console.groupEnd();
     } else {
@@ -125,18 +130,72 @@ function recieveQueryData(type, client) {
     }
     });
   } else {
-    console.group('corpus_analysis_query_results: Loading query data.')
+    console.group('corpus_analysis_query_results: Loading query data.');
     console.info('Client loading imported query data from database.');
     // executing the registered callbacks
-    client.socketEventListeners[type].executeCallbacks();
+    client.eventListeners[type].executeCallbacks();
     console.groupEnd();
   }
 }
 
+/**
+ * Recieves the data requested by the create Results or sub results button
+ */
+function recieveResultsData(type, client) {
+  client.socket.on(type, (response) => {
+    /**
+     * Check if request for session was OK.
+     * If OK execute registered callbacks and notify View.
+     */
+    if (response.code === 200) {
+      console.group('Client recieving results data')
+      console.info('corpus_analysis_inspect_match: Client recieving results data',
+      'via socket.on');
+      console.info(`corpus_analysis_inspect_match: ${response.code} - ${response.msg}`);
+      console.info(response);
+      // executing the registered callbacks
+      client.eventListeners[type].executeCallbacks([response.payload]);
+      console.groupEnd();
+    } else {
+      console.group('Failed to recieve results data.');
+      console.error('corpus_analysis_inspect_match: Client failed to recieve',
+                    'results data via socket.on');
+      let errorText = `Error ${response.payload.code} - ${response.payload.msg}`;
+      console.error(`corpus_analysis_inspect_match: ${errorText}`);
+      console.groupEnd();
+    }
+  });
+}
+
+/*
+ * This is the javascript custom event listener, listening for events
+ * dispatched by the View.
+ */
+function recieveViewNotification(type, client) {
+  document.addEventListener(type, (event) => {
+    let caseIdentifier = event.detail.caseIdentifier;
+    switch(caseIdentifier) {
+      case 'get-results':
+        console.info('Client getting full results for export.');
+        // execute callback or functions
+        client.eventListeners[type].executeCallback([event.detail.resultsType,
+                                                     event.detail.dataIndexes],
+                                                     caseIdentifier);
+        break
+        default:
+          console.error('Recieved unkown notification case identifier from View');
+          // do something to not crash the analysis session?
+          // maybe unnecessary
+    }
+  });
+}
+
 // export listeners from this module
 export {
   recieveConnected,
   recieveMetaData,
   recieveQueryStatus,
-  recieveQueryData
+  recieveQueryData,
+  recieveViewNotification,
+  recieveResultsData,
 };
\ No newline at end of file
diff --git a/web/app/static/js/modules/corpus_analysis/model/Results.js b/web/app/static/js/modules/corpus_analysis/model/Results.js
index 3e8edf7e0db157074a78147e268d69ef8460c5eb..c2f0c3bcf3e9011c817992b41a04d21a44ba80eb 100644
--- a/web/app/static/js/modules/corpus_analysis/model/Results.js
+++ b/web/app/static/js/modules/corpus_analysis/model/Results.js
@@ -8,6 +8,7 @@ class Results {
   constructor() {
   this.data = new Data();
   this.metaData = new MetaData();
+  this.fullResultsData = new Data();
   this.subResultsData = new Data();
   console.info('Initialized the Results object.');
   }
@@ -15,12 +16,12 @@ class Results {
   init() {
     this.data.init();
     this.metaData.init();
+    this.fullResultsData = new Data();
     this.subResultsData.init();
   }
 
 }
 
-
 class Data {
   // Sets empty object structure. Also usefull to delete old results.
   // matchCount default is 0
@@ -94,29 +95,6 @@ class Data {
     this.download(downloadElement, dataStr, resultFilename, "text/json", ".json")
   }
 
-  // create results data either from all results or from al lmarked sub results
-  createResultsData(type) {
-    // deactivate inspect, because cqp server cannot handle multiple requests
-    results.jsList.deactivateInspect();
-    activateInspectInteraction.setCallback("noCheck",
-                                            results.jsList.deactivateInspect,
-                                            results.jsList);
-    // set flag that results are being created to avoid reactivation of
-    // sub results creation if marked matches are changed
-    resultCreationRunning = true;
-    console.log(resultCreationRunning);
-    if (type === "sub-results") {
-      resultsCreateElement.classList.add("disabled");  // cqp server cannot handle more than one request at a time. Thus we deactivate the resultsCreateElement
-      let tmp = [...results.jsList.addToSubResultsIdsToShow].sort(function(a, b){return a-b});
-      let dataIndexes = [];
-      tmp.forEach((index) => dataIndexes.push(index - 1));
-      results.jsList.getMatchWithContext(dataIndexes, "sub-results");
-    } else if (type === "results") {
-      subResultsCreateElement.classList.add("disabled");  // cqp server cannot handle more than one request at a time. Thus we deactivate the subResultsCreateElement
-      let dataIndexes = [...Array(results.data.match_count).keys()];
-      results.jsList.getMatchWithContext(dataIndexes, "results");
-    }
-  }
 }
 
 class MetaData {
diff --git a/web/app/static/js/modules/corpus_analysis/view/ResultsView.js b/web/app/static/js/modules/corpus_analysis/view/ResultsView.js
index 146913edeab290e6f20eb1cfe122a5af9d00fa48..6eb5e5c5a3f3db59843cf783ff5affb495f588d4 100644
--- a/web/app/static/js/modules/corpus_analysis/view/ResultsView.js
+++ b/web/app/static/js/modules/corpus_analysis/view/ResultsView.js
@@ -2,7 +2,7 @@
  * This class implements a NotificationListener that is listening for the
  * specified
  */
-class NotificationListener {
+class ViewEventListener {
   constructor(type, listenerFunction) {
     this.listenerFunction = listenerFunction;
     this.type = type;
@@ -61,7 +61,7 @@ class ResultsList extends List {
    * class field in the ResultsList object with the query selector
    * string as the key. The selector will be converted to a valid JavaScript
    * Field name i. e. #html-id-string -> this.htmlIdString
-   * The value will be the identifed element fetched with the querySelector
+   * The value will be the identifed element or elements fetched with the querySelector
    * method.
    */
   // TODO: multipleResults=false, atattchSomeCallback=false ?
@@ -73,6 +73,7 @@ class ResultsList extends List {
         element = document.querySelector(selector);
       } else {
         elements = document.querySelectorAll(selector);
+        elements = [...elements];
       }
       let cleanKey = [];
       selector = selector.replace(/_/g, '-');
@@ -106,6 +107,17 @@ class ResultsList extends List {
     }
   }
 
+  /**
+   * This functions sends events to the Client to trigger specific functions to
+   * trigger new data requests from the server.
+   */
+  notifyClient(caseIdentifier, detailObject={}) {
+    detailObject.caseIdentifier = caseIdentifier;
+    const event = new CustomEvent('notify-client', { detail: detailObject });
+    console.info('Client dispatching Notification:', caseIdentifier);
+    document.dispatchEvent(event);
+  }
+
   /**
    * Creates cpos either from ranges or not.
    */
@@ -255,25 +267,6 @@ class ResultsList extends List {
     }
   }
 
-  // Triggers emit to get full match context from server for a number of
-  // matches identified by their data_index.
-  getMatchWithContext(dataIndexes, type) {
-    let tmp_first_cpos = [];
-    let tmp_last_cpos = [];
-    for (let dataIndex of dataIndexes) {
-      tmp_first_cpos.push(results.data.matches[dataIndex].c[0]);
-      tmp_last_cpos.push(results.data.matches[dataIndex].c[1]);
-    }
-    nopaque.socket.emit("corpus_analysis_inspect_match",
-                      {
-                        type: type,
-                        data_indexes: dataIndexes,
-                        first_cpos: tmp_first_cpos,
-                        last_cpos: tmp_last_cpos,
-                      }
-          );
-  }
-
   // ###### Functions to inspect one match, to show more details ######
   // activate inspect buttons if progress is 100
   activateInspect() {
@@ -786,7 +779,7 @@ class ResultsList extends List {
     return matchRowElement
   }
 
-  // creates the HTML table code for the metadata vie in the corpus analysis interface
+  // creates the HTML table code for the metadata view in the corpus analysis interface
   createMetaDataForModal(metaDataObject) {
     let html = `<div class="col s12">
                       <table class="highlight">
@@ -838,12 +831,12 @@ class ResultsList extends List {
   }
 
   // Creates the text details for the texts shown in the corpus analysis metadata modal.
-  createTextDetails(metaDataObject) {
+  createTextDetails(metaData) {
     let metadataKey = event.target.dataset.metadataKey;
     let textKey = event.target.dataset.textKey;
-    let textData = metaDataObject[metadataKey][textKey];
-    let bibliographicData = document.getElementById(`bibliographic-data-${metadataKey}-${textKey}`);
-    bibliographicData.innerHTML = "";
+    let textData = metaData[metadataKey][textKey];
+    let bibliographicData = document.querySelector(`#bibliographic-data-${metadataKey}-${textKey}`);
+    bibliographicData.textContent = '';
     for (let [key, value] of Object.entries(textData)) {
       bibliographicData.insertAdjacentHTML("afterbegin",
       `
@@ -854,4 +847,4 @@ class ResultsList extends List {
 };
 
 // export classses
-export { NotificationListener, ResultsList };
\ No newline at end of file
+export { ViewEventListener, ResultsList };
\ No newline at end of file
diff --git a/web/app/static/js/modules/corpus_analysis/view/callbacks.js b/web/app/static/js/modules/corpus_analysis/view/callbacks.js
index 46b67fb79b29cebc00c2ccbbe02e5c1548227943..d313375498934eb83bf7a247310934d8bce3bc4e 100644
--- a/web/app/static/js/modules/corpus_analysis/view/callbacks.js
+++ b/web/app/static/js/modules/corpus_analysis/view/callbacks.js
@@ -98,8 +98,14 @@ function queryDataRecievedCallback(resultsList, detail) {
   // show or enable some things for the user
   resultsList.queryResultsCreate.classList.toggle('disabled');
   resultsList.addToSubResults.removeAttribute("disabled");
+}
 
+function resultsDataRecievingCallback(resultsList, detail) {
+  // hide or disable elments taht would trigger another cqp data request
+}
 
+function resultsDataRecievedCallback(resultsList, detail) {
+  // hide or show the right stuff
 }
 
 // export the callbacks
@@ -110,4 +116,6 @@ export {
   queryDataPreparingCallback,
   queryDataRecievingCallback,
   queryDataRecievedCallback,
+  resultsDataRecievingCallback,
+  resultsDataRecievedCallback,
 };
\ No newline at end of file
diff --git a/web/app/static/js/modules/corpus_analysis/view/listeners.js b/web/app/static/js/modules/corpus_analysis/view/listeners.js
index b549a2f3641ad2a4808a19373b51776645c10e55..ff84921937d95338736b21bf541bdbf5620c783c 100644
--- a/web/app/static/js/modules/corpus_analysis/view/listeners.js
+++ b/web/app/static/js/modules/corpus_analysis/view/listeners.js
@@ -14,43 +14,55 @@ import {
   queryDataPreparingCallback,
   queryDataRecievingCallback,
   queryDataRecievedCallback,
+  resultsDataRecievingCallback,
+  resultsDataRecievedCallback,
 } from './callbacks.js';
 
-function recieveNotification(eventType, resultsList) {
+function recieveClientNotification(eventType, resultsList) {
   document.addEventListener(eventType, (event) => {
     let caseIdentifier = event.detail.caseIdentifier;
     switch (caseIdentifier) {
       case 'connecting':
-        console.info('Recieved notification:', caseIdentifier);
+        console.info('View recieved notification:', caseIdentifier);
         connectingCallback(resultsList, event.detail);
         // execute callback
         break;
       case 'connected':
-        console.info('Recieved notification:', caseIdentifier);
+        console.info('View recieved notification:', caseIdentifier);
         connectedCallback(resultsList, event.detail);
         break;
       case 'connecting-failed':
-        console.info('Recieved notification:', caseIdentifier);
+        console.info('View recieved notification:', caseIdentifier);
         // execute callback
         connectingFaildeCallback(resultsList, event.detail);
         break;
       case 'query-data-prepareing':
-        console.info('Recieved notification:', caseIdentifier);
+        console.info('View recieved notification:', caseIdentifier);
         // execute callback
         queryDataPreparingCallback(resultsList, event.detail);
         break;
       case 'query-data-recieving':
-        console.info('Recieved notification:', caseIdentifier);
+        console.info('View recieved notification:', caseIdentifier);
         // execute callback
         queryDataRecievingCallback(resultsList, event.detail);
         break;
       case 'query-data-recieved':
-        console.info('Recieved notification:', caseIdentifier);
+        console.info('View recieved notification:', caseIdentifier);
         // execute callback
         queryDataRecievedCallback(resultsList, event.detail);
         break;
+      case 'results-data-recieving':
+        console.info('View recieved notification:', caseIdentifier);
+        // execute callback
+        resultsDataRecievedCallback(resultsList, event.detail);
+        break;
+      case 'results-data-recieved':
+        console.info('View recieved notification:', caseIdentifier);
+        // execute callback
+        resultsDataRecievedCallback(resultsList, event.detail);
+        break;
       default:
-        console.error('Recieved unkown notification case identifier');
+        console.error('Recieved unkown notification case identifier from Client');
         // do something to not crash the analysis session?
         // maybe unnecessary
     }
@@ -58,4 +70,4 @@ function recieveNotification(eventType, resultsList) {
 }
 
 // export listeners
-export { recieveNotification };
\ No newline at end of file
+export { recieveClientNotification };
\ No newline at end of file
diff --git a/web/app/static/js/modules/corpus_analysis/view/spinner.js b/web/app/static/js/modules/corpus_analysis/view/spinner.js
new file mode 100644
index 0000000000000000000000000000000000000000..5c4b7422da3ddb62b8abba5996af88e7419c6c11
--- /dev/null
+++ b/web/app/static/js/modules/corpus_analysis/view/spinner.js
@@ -0,0 +1,17 @@
+// loading spinner animation HTML
+const loadingSpinnerHTML = `
+            <div class="preloader-wrapper button-icon-spinner small active">
+              <div class="spinner-layer spinner-green-only">
+                <div class="circle-clipper left">
+                  <div class="circle"></div>
+                  </div><div class="gap-patch">
+                  <div class="circle"></div>
+                  </div><div class="circle-clipper right">
+                  <div class="circle"></div>
+                </div>
+              </div>
+            </div>
+            `;
+
+//export
+export { loadingSpinnerHTML };
diff --git a/web/app/templates/corpora/analyse_corpus.html.j2 b/web/app/templates/corpora/analyse_corpus.html.j2
index 3b932839eec2fb87896a4ab3752aed31aaaa1e00..09e7b6fbd21cf8b54bcf2eb21718d0b434371849 100644
--- a/web/app/templates/corpora/analyse_corpus.html.j2
+++ b/web/app/templates/corpora/analyse_corpus.html.j2
@@ -70,35 +70,45 @@
  * First Phase:
  * Document content is loaded and scripts are being imported and executed.
  */
+ // import Client classes
 import {
   Client,
-  SocketEventListener,
+  ClientEventListener,
   ListenerCallback,
 } from '../../static/js/modules/corpus_analysis/client/Client.js';
+// import client listener functions
 import {
   recieveConnected,
   recieveMetaData,
   recieveQueryStatus,
   recieveQueryData,
+  recieveViewNotification,
+  recieveResultsData,
 } from '../../static/js/modules/corpus_analysis/client/listeners.js';
-import {
-  Results,
-} from '../../static/js/modules/corpus_analysis/model/Results.js';
+// import client listener callbacks
 import {
   prepareQueryData,
   saveQueryData,
   saveMetaData,
+  getResultsData,
+  saveResultsData,
 } from '../../static/js/modules/corpus_analysis/client/callbacks.js';
 import {
-  NotificationListener,
+  Results,
+} from '../../static/js/modules/corpus_analysis/model/Results.js';
+import {
+  ViewEventListener,
   ResultsList,
 } from '../../static/js/modules/corpus_analysis/view/ResultsView.js';
 import {
-  recieveNotification,
+  recieveClientNotification,
 } from '../../static/js/modules/corpus_analysis/view/listeners.js';
 import {
   scrollToTop,
 } from '../../static/js/modules/corpus_analysis/view/scrollToTop.js'
+import {
+  loadingSpinnerHTML,
+} from '../../static/js/modules/corpus_analysis/view/spinner.js'
 
 /**
  * Second Phase:
@@ -120,44 +130,59 @@ document.addEventListener("DOMContentLoaded", () => {
   let resultsList = new ResultsList('result-list', ResultsList.options);
   /**
   * Register listeners listening to socket.io events and their callbacks
-  * Afterwards load them.
+  * Afterwards load them. Also registers listeners listening for custom
+  * javascript events.
   */
-  const listenForConnected = new SocketEventListener('corpus_analysis_init',
+  const listenForConnected = new ClientEventListener('corpus_analysis_init',
                                                      recieveConnected);
-  const listenForMetaData = new SocketEventListener('corpus_analysis_meta_data',
+  const listenForMetaData = new ClientEventListener('corpus_analysis_meta_data',
                                                     recieveMetaData);
   const metaDataCallback = new ListenerCallback('corpus_analysis_meta_data',
                                                 saveMetaData,
                                                 [client, results]);
   listenForMetaData.setCallbacks([metaDataCallback]);
-  const listenForQueryStatus = new SocketEventListener('corpus_analysis_query',
+  const listenForQueryStatus = new ClientEventListener('corpus_analysis_query',
                                                        recieveQueryStatus);
   const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
                                                    prepareQueryData,
                                                    [client, results]);
   listenForQueryStatus.setCallbacks([queryStatusCallback]);
-  const listenForQueryData = new SocketEventListener('corpus_analysis_query_results',
+  const listenForQueryData = new ClientEventListener('corpus_analysis_query_results',
                                                      recieveQueryData);
   const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
                                                  saveQueryData,
                                                  [client, results]);
   listenForQueryData.setCallbacks([queryDataCallback]);
+  const listenForResults = new ClientEventListener('corpus_analysis_inspect_match',
+                                                   recieveResultsData);
+  const resultsDataCallback = new ListenerCallback('corpus_analysis_inspect_match',
+                                                   saveResultsData,
+                                                   [client, results]);
+  listenForResults.setCallbacks([resultsDataCallback]);
+  // listen for javascript custom notifications
+  const listenForViewNotification = new ClientEventListener('notify-client',
+                                                            recieveViewNotification);
+  const getResultsCallback = new ListenerCallback('get-results',
+                                                  getResultsData,
+                                                  [client, results]);
+  listenForViewNotification.setCallbacks([getResultsCallback]);
   client.setSocketEventListeners([listenForConnected,
                                   listenForQueryStatus,
                                   listenForQueryData,
-                                  listenForMetaData]);
+                                  listenForMetaData,
+                                  listenForViewNotification,
+                                  listenForResults]);
   client.loadSocketEventListeners();
   /**
   * Register resultsList listeners listening to nitification events.
   */
-  const listenForNotification = new NotificationListener('notify',
-                                                         recieveNotification);
-  resultsList.setNotificationListeners([listenForNotification]);
+  const listenForClientNotification = new ViewEventListener('notify-view',
+                                                            recieveClientNotification);
+  resultsList.setNotificationListeners([listenForClientNotification]);
   resultsList.loadNotificationListeners();
   // Connect client to server
   client.notifyView('connecting');
   client.connect();
-
   // Send a query and recieve its answer data
   let queryFormElement = document.querySelector('#query-form');
   queryFormElement.addEventListener('submit', (event) => {
@@ -181,20 +206,66 @@ document.addEventListener("DOMContentLoaded", () => {
     results.data.getQueryStr(queryFormElement);
     client.query(results.data.query);
   });
-  /**
-   * Display events
-   * 1. live update of hits per page if hits per page value is changed
-   */
+  // Get all needed HTMLElements for the following event listeners
   resultsList.getHTMLElements([
     '#display-options-form-results_per_page',
-    '#display-options-form-result_context'
+    '#display-options-form-result_context',
+    '#show-meta-data',
+    '#meta-data-modal',
+    '#meta-data-modal-content',
+    '#query-results-create'
+
   ]);
+  /**
+   * Display events: Following event listeners are handleing the
+   * live update of hits per page if hits per page value is changed and the
+   * context size of every match.
+   */
   resultsList.displayOptionsFormResultsPerPage.onchange = () => {
     resultsList.changeHitsPerPage();
   };
   resultsList.displayOptionsFormResultContext.onchange = () => {
     resultsList.changeContext();
   };
+  /**
+   * The following event listener handel the Show metadata button and its
+   * functionality. Before the needed modal is initialized.
+   */
+  let deleteOverlay = () => {
+    let overlay = document.querySelector(".modal-overlay");
+    overlay.remove();
+  };
+  resultsList.metaDataModal= M.Modal.init(resultsList.metaDataModal, {
+    'preventScrolling': false,
+    'opacity': 0.0,
+    'dismissible': false,
+    'onOpenEnd': deleteOverlay
+  });
+  resultsList.showMetaData.onclick = () => {
+    resultsList.metaDataModalContent.textContent = '';
+    let table = resultsList.createMetaDataForModal(results.metaData);
+    resultsList.metaDataModalContent.insertAdjacentHTML('afterbegin', table);
+    resultsList.metaDataModal.open();
+    let collapsibles = resultsList.metaDataModalContent.querySelectorAll(".text-metadata");
+    for (let collapsible of collapsibles) {
+      collapsible.onclick = () => {
+        let elems = resultsList.metaDataModalContent.querySelectorAll('.collapsible');
+        let instances = M.Collapsible.init(elems, {accordion: false});
+        resultsList.createTextDetails(results.metaData);
+      }
+    }
+  };
+  /**
+   * The following event listeners are handeling the data export.
+   */
+  resultsList.queryResultsCreate.onclick = () => {
+    resultsList.queryResultsCreate.querySelector('i').classList.toggle('hide');
+    resultsList.queryResultsCreate.innerText = 'Creating...';
+    resultsList.queryResultsCreate.insertAdjacentHTML('afterbegin',
+                                                      loadingSpinnerHTML);
+    resultsList.notifyClient('get-results', { resultsType: 'full-results',
+                                              dataIndexes: [...Array(results.data.match_count).keys()]});
+  }
 
 
 
diff --git a/web/app/templates/interactions/infos.html.j2 b/web/app/templates/interactions/infos.html.j2
index 409c5338c8affd4b811b8a6d5e5d9926fa38f6bd..43cf41bb3959829825b52d513eec05cca16cdf5f 100644
--- a/web/app/templates/interactions/infos.html.j2
+++ b/web/app/templates/interactions/infos.html.j2
@@ -7,7 +7,7 @@ result.-->
   <div class="divider" style="margin-bottom: 10px;"></div>
   <div class="row">
     <div class="col s12">
-      <button id="show-metadata"
+      <button id="show-meta-data"
               class="waves-effect
                      waves-light
                      btn-flat