-
Notifications
You must be signed in to change notification settings - Fork 4
Loading of Resources
content is up-to-date for ccmjs v26.4.1
- Introduction
- Syntax
- Parameter Values
- Technical Details
-
Detailed Explanation
- Simplest Case: Loading by URL
- Loading by Resource Data Object
- Result of a ccm.load Call
- Error Handling
- Loading with Timeout
- Loading of Multiple Resources at Once
- Parallel and Serial Loading of Resources
- Loading of JavaScript
- Loading of Data
- Loading a Resource Regardless of its File Extension
- Other Aspects
-
More Examples
- Loading the Content of an HTML File with a Relative Path
- Loading the Content of an JSON File with an Absolute Path
- Loading of HTML as HTML String
- Loading of a CSS File in the <head> Context
- Loading of a CSS File in a Shadow DOM Context
- Loading of a CSS File in the Shadow DOM of a ccmjs Instance
- Preloading of an Image
- Loading of a JavaScript Library
- Loading of a JavaScript File with Subresource Integrity
- Cross-domain Loading of Static JSON through a JavaScript File
- Dynamic Loading of an Image
- Dynamic Loading of JavaScript
- POST Request via Fetch API
- Loading of a static XML file
- Loading of a Module
- Loading of a Function via a Module
The ccmjs core script provides a service for asynchronous loading of resources.
It could be used with the method ccm.load
.
With ccm.load
you can load resources like HTML, CSS, Images, JavaScript, Modules, JSON and XML data on-demand and cross-domain.
On a single ccm.load
call several resources can be loaded at once.
It can be flexibly controlled which resources are loaded in serial and which in parallel.
The results are passed as a Promise
. So you can also use ccm.load
with async await
. Everything that can be loaded via ccm.load
can also be specified as resource dependency like [ 'ccm.load', ... ]
in configurations for ccmjs-based component instances and is therefore flexibly exchangeable.
ccm.load( resource1, resource2, ..., resourceX )
Parameter | Description |
---|---|
resource1, resource2, ..., resourceX |
The resources to be loaded. |
Return Value
- Promise that provides the result(s) of the
ccm.load
call
JavaScript Version:
- ECMAScript 6
In the following, all aspects of how to use ccm.load
are described in detail.
In the simplest case, only an URL is passed as a parameter for a resource to be loaded:
ccm.load( 'style.css' );
The URL of the resource can be a relative or an absolute path. The resource does not have to be within the same domain and can be loaded cross-domain.
Instead of an URL, an object can be passed, which then contains other information besides the URL, via which the loading of the resource is even more flexible controllable. For example, when loading a resource, it can be specified in which context it is loaded. The CSS contained in a CSS file can now also be loaded into a specific Shadow DOM:
const shadow = document.createElement( 'div' );
shadow.attachShadow( { mode: 'open' } );
ccm.load( { url: 'style.css', context: shadow } );
See here, here and here for more examples of loading CSS.
Here is a list of settings that can be made for loading a resource via such an object:
Property | Description |
---|---|
url | Required. URL of the resource. |
context | Context in which the resource should be loaded (default is <head> ). |
method | HTTP method to use: 'PUT' , 'GET' , 'POST' , 'DELETE' , 'fetch' or 'JSONP' (default is 'POST' ). |
params | HTTP parameters to send (in the case of a data exchange). |
headers | HTTP headers to be set in the case of a HTTP request. |
attr | HTML attributes to be set for the HTML tag that loads the resource. |
init |
init object. Only relevant when using the Fetch API (method: 'fetch' ). |
import | Name of the exported property to be imported. Only relevant when loading an ES6 module. If not specified, all exported things of the module are imported. |
type | Resource is loaded as 'css' , 'data' , 'html' , 'image' , 'js' , 'module' or 'xml' . If not specified, the type is automatically recognized by the file extension. If the file extension is unknown, 'data' is used by default. |
ccm.load
returns a Promise
that provides the result(s) of the ccm.load
call.
The following example loads the content "Hello, <b>World</b>!"
of a HTML file:
Promise
ccm.load( 'hello.html' ).then( result => {} );
async await
const result = await ccm.load( 'hello.html' );
The variable result
then contains the HTML as ccmjs HTML Data:
{
"inner": [
"Hello, ",
{
"inner": "World",
"tag": "b"
},
"!"
]
}
With ccm.helper.html( result )
the HTML can be converted to DOM Elements.
If loading of at least one resource fails, the resulting Promise
will be rejected.
Promise
ccm.load( 'not_exits.html' ).catch( error => {} );
async await
try {
await ccm.load( 'not_exists.html' );
}
catch ( error ) {}
The variable error
then contains an object with informations about the error.
The following table shows what information this object contains:
Property | Description |
---|---|
call | Action Data of the original method call |
data | Object of the XMLHttpRequest |
error | Error Object of the failed XMLHttpRequest |
resource | Passed Resource Data Object |
In case of a XMLHttpRequest the HTTP status code and the response text can be checked via data
and with error
you can get the responded error message:
try {
await ccm.load( 'not_available.html' );
}
catch ( error ) {
if ( error.data.status === 404 ) // not found?
alert( error.error.message ); // => show error message of XMPHttpRequest
else if ( error.data.responseText ) // error with response text?
alert( error.data.responseText ); // => show response text
else
alert( 'Something went wrong' );
}
Watch the error
variable in the Developer Console to see what other useful data is included.
For loading resources, a timeout can be set:
ccm.load.timeout = 10000; // timeout after 10s
In this example, resources that last longer than 10 seconds would fail. By default, there is no time limit. If a result is received after the timeout has expired, a message like this appears in the Developer Console:
[ccm] loading of https://my.domain/bigdata.php succeeded after timeout (10000ms)
On a single ccm.load
call several resources can be loaded at once:
const results = await ccm.load( 'hello.html', 'style.css', 'image.png' );
When multiple resources are loaded, the Promise
provides an array instead of a single value as the result.
The array contains the results in the order in which the parameters were passed.
In this example the variable results
contains:
[ {"inner":["Hello, ",{"inner":"World","tag":"b"},"!"]}, "style.css", "image.png" ]
.
If loading a resource does not supply anything specific, the default result is the URL of the resource. This applies, for example, when loading CSS and images.
If loading one of the resources fails, the result is still an array. For failed resources, the array will contain the error object instead of the result:
try {
await ccm.load( 'not_exists.html', 'style.css', 'image.png' );
}
catch ( error ) {
console.log( error ); // [ {error object}, "style.css", "image.png" ]
}
It can be flexibly controlled which resources are loaded serially and which ones in parallel. By default, resources are loaded in parallel. When resources are to be loaded one after another, they simply need to be passed as an array:
ccm.load( [ 'hello.html', 'style.css' ] );
In the example, the two resources are now loaded serially.
The serial and parallel loading can be flexibly controlled as deep as desired. With each deeper array level you switch between serial and parallel loading:
ccm.load(
'hello.html', // Array Level 0: Parallel
[
'style.css', // Array Level 1: Serial
'image.png',
[
'data.json', // Array Level 2: Parallel
'script.js'
],
'logo.gif'
],
'picture.jpg'
);
The example loads the resources in the following timeline:
Resource | Timeline |
---|---|
hello.html |
******------------------ |
style.css |
******------------------ |
image.png |
------******------------ |
data.json |
------------******------ |
script.js |
------------******------ |
logo.gif |
------------------****** |
picture.jpg |
******------------------ |
Loading a JavaScript file will execute the JavaScript code contained in the file.
As a result of this resource ccm.load
returns the URL as usual.
But the loaded JavaScript code can also set the result individually:
/* script.js */
ccm.files[ 'script.js' ] = { foo: 'bar' };
const result = await ccm.load( 'script.js' );
Loading this JavaScript file with ccm.load
results in: { foo: 'bar' }
.
ccm.load
returns as a result of loading a JavaScript file what the contained JavaScript code puts in ccm.files[ 'filename' ]
, where filename is the filename of the JavaScript file.
Otherwise, the result is the URL.
Using this convention, a JavaScript file can provide data across domains.
Publicly fetched data in the global namespace ccm.files
will be immediately deleted by ccmjs.
In case of a minimized JavaScript file, ".min" in filename can be omitted:
/* script.min.js */
ccm.files['script.js']={foo:'bar'};
const result = await ccm.load( 'script.min.js' );
See here, here and here for more examples of loading JavaScript.
Data can be loaded via ccm.load
:
const result = await ccm.load( 'hello.php' );
/* hello.php */
<?php
echo 'Hello, World!';
?>
This example results in: "Hello, World!"
A Resource Data Object can be used to specify HTTP parameters to be transmitted:
const result = await ccm.load( {
url: 'echo.php',
params: { // sets HTTP parameters
name: 'John'
}
} );
/* echo.php */
<?php
echo 'Hello, '.filter_input( INPUT_POST, 'name', FILTER_SANITIZE_STRING );
?>
This example results in: "Hello, John!"
The Resource Data Object can also be used to specify whether GET
or POST
should be used as HTTP method:
const result = await ccm.load( {
url: 'hello.php',
method: 'GET' // sets HTTP method
} );
By default, POST
is used.
JSONP can be used for data exchange.
In this case, it is always a GET
request.
JSONP is only necessary if the data has to be loaded cross-domain:
const result = await ccm.load( {
url: 'https://other.domain.com/data.php',
method: 'JSONP' // turns on JSONP
} );
/* data.php */
<?php
$callback = filter_input( INPUT_GET, 'callback', FILTER_SANITIZE_STRING );
echo $callback.'({"foo":"bar"});';
?>
This example results in: { "foo": "bar" }
JSONP is not required if Cross-origin Resource Sharing (CORS) is already working.
Normally ccm.load
automatically recognizes at the file extension how the resource should be loaded.
If a type
is specified in the Resource Data Object, the file extension of the resource is ignored and the resource is loaded as the specified type:
ccm.load( {
url: 'style.php',
type: 'css' // resource is loaded as CSS file
} );
/* style.php */
<?php
header( 'Content-Type: text/css' );
?>
b { color: red; }
Although the resource does not have the file extension .css
, it will be loaded like a CSS file.
The <head>
now contains: <link rel="stylesheet" type="text/css" href="style.php">
.
If type
is not specified and the file extension is unknown, a data exchange is assumed.
See here and here for another examples of loading a resource regardless of its file extension.
All Resource Data Objects passed to ccm.load
are cloned to prevent them from being changed externally.
In a Resource Data Object, the reference to a ccmjs Instance can also be passed for the property context
.
The resource is then loaded into the instance's Shadow DOM.
When a resource is loaded into a specific context, care must be taken that this context has DOM contact. The chosen context should not be an on-the-fly element or part of it. This is required so that the HTML element used to load the resource is evaluated by the browser.
const result = await ccm.load( 'https://ccmjs.github.io/ccm/unit_tests/dummy/hello.html' );
/* hello.html */
Hello, <b>World</b>!
Result:
{"inner":["Hello, ",{"inner":"World","tag":"b"},"!"]}
.
const data = await ccm.load( 'https://ccmjs.github.io/ccm/unit_tests/dummy/data.json' );
/* data.json */
{ "foo": "bar" }
Result: { "foo": "bar" }
If you want to load the static data from a JSON file cross-domain, the data should instead be provided via a JavaScript file (see here and here). Then the static data is loaded with JSONP and the HTTP request is not blocked by the Same-origin Policy (SOP) of the browser. JSONP is not required if Cross-origin Resource Sharing (CORS) is already working.
const html_string = await ccm.load( {
"url": "https://ccmjs.github.io/ccm/unit_tests/dummy/hello.html",
"type": "data"
} );
Result: Hello, <b>World</b>!
With ccm.helper.html2json( html_string )
you can transform the HTML string to ccmjs HTML data.
await ccm.load( 'https://ccmjs.github.io/ccm/unit_tests/dummy/style.css' );
The CSS rules contained in the CSS file are now active inside the global DOM.
The <head>
now contains:
<link rel="stylesheet" type="text/css" href="https://ccmjs.github.io/ccm/unit_tests/dummy/style.css">
Loading of a CSS File in a Shadow DOM Context
const shadow = document.createElement( 'div' );
shadow.attachShadow( { mode: 'open' } );
ccm.load( {
url: 'https://ccmjs.github.io/ccm/unit_tests/dummy/style.css',
context: shadow
} );
This time the CSS rules contained in the CSS file are now active inside the Shadow DOM and the <link>
element is appended to the shadow-root of shadow
.
Loading of a CSS File in the Shadow DOM of a ccmjs Instance
const instance =
await ccm.instance( 'https://ccmjs.github.io/akless-components/blank/ccm.blank.js' );
ccm.load( {
url: 'https://ccmjs.github.io/ccm/unit_tests/dummy/style.css',
context: instance
} );
The CSS rules contained in the CSS file are now active inside the Shadow DOM of the ccmjs Instance and the <link>
element is appended to its shadow-root.
await ccm.load( 'https://ccmjs.github.io/ccm/unit_tests/dummy/image.png' );
When the resulting Promise
is resolved, the loaded image is in the browser cache.
This example loads the JavaScript library jQuery v3.2.1.
ccm.load( 'https://code.jquery.com/jquery-3.2.1.js' );
The code contained in the loaded JavaScript file is now executed and the <head>
contains:
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
Loading of a JavaScript File with Subresource Integrity
This is also an example of setting HTML attributes for the HTML tag that loads a resource.
ccm.load( {
url: 'https://ccmjs.github.io/ccm/unit_tests/dummy/script.js',
attr: {
integrity: 'sha384-QoLtnRwWkKw2xXw4o/pmW2Z1Zwst5f16sRMbRfP/Ova1nnEN6t2xUwiLOZ7pbbDW',
crossorigin: 'anonymous'
}
} );
The <head>
now contains:
<script src="https://ccmjs.github.io/ccm/unit_tests/dummy/script.js"
integrity="sha384-QoLtnRwWkKw2xXw4o/pmW2Z1Zwst5f16sRMbRfP/Ova1nnEN6t2xUwiLOZ7pbbDW"
crossorigin="anonymous"></script>
const json = await ccm.load( 'https://ccmjs.github.io/ccm/unit_tests/dummy/script.js' );
/* script.js */
ccm.files[ 'script.js' ] = { foo: 'bar' };
Result: { "foo": "bar" }
This example preloads an image that comes from a PHP interface.
ccm.load( {
url: 'https://kaul.inf.h-brs.de/ccm/dummy/image.php',
type: 'image'
} );
<?php
header( 'Content-Type: image/png' );
readfile( 'image.png' );
?>
If the PHP interface would additionally implement user authentication, images could be made available to specific user groups. An HTTP parameter could also be used to control which image should be delivered.
This example loads JavaScript that comes from a PHP interface.
const result = await ccm.load( {
url: 'https://kaul.inf.h-brs.de/ccm/dummy/js.php',
type: 'js'
} );
/* js.php */
ccm.files[ 'js.php' ] = { foo: '<? echo 'bar'; ?>' };
console.log( 'Hello, <? echo 'World'; ?>!' );
The <head>
now contains: <script src="https://kaul.inf.h-brs.de/ccm/dummy/js.php">
.
Result in the Developer Console: Hello, World!
Result of the resolved Promise: { "foo": "bar" }
POST Request via Fetch API
const result = await ccm.load( {
url: './api/projects',
method: 'fetch',
init: {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify( {
title: 'Example Project',
url: 'http://www.example.com'
} )
}
} );
const result = await ccm.load( 'https://ccmjs.github.io/ccm/unit_tests/dummy/note.xml' );
/* note.xml */
<note>
<foo>bar</foo>
</note>
Result: #document
"<note><foo>bar</foo></note>"
If you want to load the static data from a XML file cross-domain, the data should instead be provided via a JavaScript file (see here and here). Then the static data is loaded with JSONP and the HTTP request is not blocked by the Same-origin Policy (SOP) of the browser. JSONP is not required if Cross-origin Resource Sharing (CORS) is already working.
const result = await ccm.load( 'https://ccmjs.github.io/akless-components/modules/helper.mjs' );
When loading a Module, the result is an object that contains all things that are exported in the Module.
In this example result
contains helper functions.
const sleep = await ccm.load( 'https://ccmjs.github.io/akless-components/modules/helper.mjs#sleep' );
/* helper.mjs.js */
...
export function sleep( time ) {
return new Promise( resolve => setTimeout( resolve, time ) );
}
...
The result is the helper function sleep
from the loaded Module. It can now be called like that:
await sleep( 10000 ); // wait 10 seconds
So in ccmjs it's possible to specify single interchangeable external JavaScript functions as dependencies in the configuration to a ccmjs-based component instance.