I'm coding using Angular 2 (Typescript) and on my webpage I have different forms with inputs and when I submit those forms they trigger their own function that adds a new instance of an object based on the inputs to an array, which is then reflected in a table on the page that is generated from said array. How can I permanently save those changes in the array after the page is refreshed. The array DPS is imported from another directory. The submitForm function is in a Typescript file of a component that's separate from the Typescript and component of the main page (the HTML and rest of the Typescript). Below, you'll see my use of onload="myFunction()" for my overall container on the main page and the myFunction() function as well.
Here's the function that adds to the array:
submitForm(value: any){
var val1 = String((<HTMLInputElement>document.getElementById("dataPoint")).value);
var val2 = String((<HTMLInputElement>document.getElementById("ICCP")).value);
var val3 = String((<HTMLInputElement>document.getElementById("startDate")).value);
var val4 = String((<HTMLInputElement>document.getElementById("endDate")).value);
let blah = new DataTable(val1,val2,val3,val4);
DPS.push(blah);
localStorage.setItem("DPS", JSON.stringify(DPS));
}
div for my main page:
<div class="container-fluid page" onload="myFunction()">
myFunction():
myFunction(){
let DPS = localStorage.getItem("DPS");
if (DPS) {
localStorage.removeItem("DPS");
DPS = JSON.parse(DPS);
}
}
You can save it in the localStorage:
...
DPS.push(blah);
localStorage.setItem("DPS", JSON.stringfy(DPS));
And on page load you can check if you already have it:
let DPS = localStorage.getItem("DPS");
if (DPS) {
localStorage.removeItem("DPS");
DPS = JSON.parse(DPS);
// you have an intance
}
Edit
Seems that there's a library for local storage in angular2: angular2-localstorage.
Related
I am trying to dynamically load data into the body of my modal but cannot seem to get it to work.
function legend(mb) {
var url = mb;
var location = document.getElementById("choice2");
var gwc = location.options[location.selectedIndex].value;
if (gwc == 15)
{
title = ['<strong>Geomorphology</strong>'];
var url = 'http://localhost/geoserver/apib/wms?REQUEST=GetLegendGraphic&VERSION=1.1.0&FORMAT=image/png&WIDTH=20&HEIGHT=25&LAYER=apib:chamapwathi_block_gm&legend_options=fontSize:14';
}
}
Considering you have only the javascript tag there, I am adding a basic javascript solution. In my example, content changes on button click, which you would have to do when you get the data from your API call.
I have also added an id attribute to the modal body.
document.getElementById('left-modal-body').innerHTML = 'Hello';
Updated Example
I'm writing a website using VueJS which allows (selected) users to add scripts that are automatically executed upon page load. Here's a sample text that a user might upload:
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.5/howler.js"></script>
<script>
var sound = new howler.Howl({
src: ['./sample.mp3']
)}.play();
</script>
This text is stored into a string after retrieving from API backend. The problem now is: I couldn't get it to execute however I try. Is there an option in VueJS that can automatically execute javascripts in strings?
As a reference, here's my code:
var temp_arr = utils.preprocess(vm.chapterInfo.Content)
vm.display = temp_arr[0]
vm.control_script = console.log(temp_arr[1])
// None of below worked
eval(vm.control_script)
document.getElementsByTagName("head")[0].appendChild(control_script)
The problem isn't a Vue one, but a JavaScript one.
I assume that you already understand the security implications of allowing users to run JavaScript; it's rarely a good idea. Sites like JSFiddle do it successfully, however it will take a lot of work and understanding to make it safe, so if you're not 100% sure with what you are doing, then as #WaldemarIce said, you shouldn't do it!
Right, with the warning out the way, you need to do a few things to get this to work:
1) Load the external scripts:
loadScripts() {
return new Promise(resolve => {
let scriptEl = document.createElement("script");
scriptEl.src = "https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.5/howler.js";
scriptEl.type = "text/javascript";
// Attach script to head
document.getElementsByTagName("head")[0].appendChild(scriptEl);
// Wait for tag to load before promise is resolved
scriptEl.addEventListener('load',() => {
resolve();
});
});
}
Here I'm simply attaching the external script to the head of the document and attaching a load event, which resolves the Promise when loaded.
2) Now we have loaded the external script we can execute the remainder of the script. You will need to strip out the script tags, so you can do something like this:
executeScript() {
// remove script tags from string (this has been declared globally)
let script = string.replace(/<\/?script>/g,"")
eval(script)
}
Form the Vue perspective, you can then execute this inside the created hook:
created() {
this.loadScripts().then(() => {
this.executeScript();
});
},
I'll leave it to you to extract the external scripts you want to load from your user input, but here's a JSFiddle: https://jsfiddle.net/49dq563d/
I recently came across this problem and had to extend on the answer from #craig_h. The example below allows full embed code to be sent through as string (HTML elements as well as scripts and inline JS). This is using DOMParser.
<div ref="htmlDump"></div>
<script>
import Vue from "vue";
export default {
...
methods: {
cloneAttributes(element, sourceNode) {
let attr;
let attributes = Array.prototype.slice.call(sourceNode.attributes);
while(attr = attributes.pop()) {
element.setAttribute(attr.nodeName, attr.nodeValue);
}
}
},
mounted(){
if(this.embedString && this.embedString.length > 0)
{
//Parse the code given from the API into a new DOM so we can easily manipulate it
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(this.embedString, 'text/html');
//Get the contents of the new DOM body and loop through.
//We want to add all HTML elements to the page and run / load all JS
var kids = [...htmlDoc.body.children];
let len = kids.length;
for (var i = 0; i < len; i++) {
var item = kids[i];
if(item.tagName == "SCRIPT")
{
//If we have a 'src' attribute then we're loading in a script
if(item.hasAttribute('src'))
{
//Create a new element within the current doc to trigger the script load
let scriptEl = document.createElement("script");
//Copy all attributes from the source element to the new one
this.cloneAttributes(scriptEl, item);
//Attach script to the DOM to trigger it to load
this.$refs.htmlDump.appendChild(scriptEl);
} else {
//if we don't have a 'src' attribute then we have some code to run
eval(item.innerText);
}
} else{
this.$refs.htmlDump.appendChild(item);
}
}
}
}
...
}
</script>
I'm working on themeing/skining of website using Absurd.js. I have theme data stored in data1.js, data2.js, data3.js and so on which passes data to the controller.js file. Changing the variable values affects the entire site with the values. Moreover we are using MultiTenant platform, where controller is one common file and data is dependent on instance of main branch. Each instance is for each client and have their own skinning (skin comes from data file).
Challenge I'm facing is, if I add a new parameter to one data file, I have to update/add all the data.js file with that parameter. Add it to the function call and as well update my contoller.js file to receive that new parameter. Its becoming tedious.
Question: Is there any tool out there to help with the file synchronization
To be more clear here is the sample file
data1.js
========
var primaryThemeColor = "#343344";
/* Primary Button Theme Colors*/
var primaryBtnBgColor = "#1A7483";
var primaryBtnBgHoverColor = "#0e233b";
var primaryBtnBorderColor = "#0093D2";
var primaryBtnFontColor = "#1A3567";
var primaryBtnFontHoverColor = "#D1ECF2";
skinComponent(primaryThemeColor,
primaryBtnBgColor,
primaryBtnBgHoverColor,
primaryBtnBorderColor,
primaryBtnFontColor,
primaryBtnFontHoverColor);
data2.js
var primaryThemeColor = "#413098";
/* Primary Button Theme Colors*/
var primaryBtnBgColor = "#38471A";
var primaryBtnBgHoverColor = "#b332e0";
var primaryBtnBorderColor = "#2d3300";
var primaryBtnFontColor = "#671A33";
var primaryBtnFontHoverColor = "#D3D3D3";
skinComponent(primaryThemeColor,
primaryBtnBgColor,
primaryBtnBgHoverColor,
primaryBtnBorderColor,
primaryBtnFontColor,
primaryBtnFontHoverColor);
data3.js, data4.js and so on... Here is my controller file
contoller.js
============
constructor: function(primaryThemeColor,
primaryBtnBgColor,
primaryBtnBgHoverColor,
primaryBtnBorderColor,
primaryBtnFontColor,
primaryBtnFontHoverColor){
this.primaryThemeColor = primaryThemeColor;
this.primaryBtnBgColor = primaryBtnBgColor;
this.primaryBtnBgHoverColor = primaryBtnBgHoverColor;
this.primaryBtnBorderColor = primaryBtnBorderColor;
this.primaryBtnFontColor = primaryBtnFontColor;
this.primaryBtnFontHoverColor = primaryBtnFontHoverColor;
});
You could do something like this. Although I feel like this is ill suited for a large amount of variations... I would imagine serving them with a persistant storage solution with a DB would be the best if these became too numerous.
var primaryThemeColor = ['#343344','#413098','#FFFFFF'];
/* Primary Button Theme Colors*/
var primaryBtnBgColor = ['#38471A','#38471A','#FFFFFF'];
var primaryBtnBgHoverColor = ['#0e233b','#b332e0','#FFFFFF'];
//...
var choice = 1; //or 0 or 2
//...
constructor: function(primaryThemeColor[choice],
primaryBtnBgColor[choice],
primaryBtnBgHoverColor[choice],
Merging the "controller" and "skinning" into one js object would enable you to implement that object across multiple js files where you could change the properties. This would provide a more reusable piece of code than what you have currently.
Since you're using jQuery, consider using a jQuery extension/widget so you can make use of the library's selectors. You could certainly do this with pure javascript as well.
Here's an example of a jQuery extension:
/// START PLUGIN:
(function($) {
$.fn.skinnify = function(options) {
// default settings
// data1
var defaults = {
primaryThemeColor: "#343344",
primaryBtnBgColor: "#1A7483",
primaryBtnBgHoverColor: "#0e233b",
primaryBtnBorderColor: "#0093D2",
primaryBtnFontColor: "#1A3567",
primaryBtnFontHoverColor: "#D1ECF2"
};
// extend the settings to include "options"
var settings = $.extend({}, defaults, options);
return this.each(function() {
// you'd need to do all of them...
$(this).css({
"background-color": settings.primaryBtnBgColor,
"border-color:": settings.primaryBtnBorderColor,
"color": settings.primaryBtnBorderColor
});
// hover is interesting...
$(this).on('hover', function() {
$(this).css({
"color": settings.primaryBtnFontHoverColor,
"cursor": "pointer",
});
});
});
};
}(jQuery));
/// END PLUGIN
// DATA.js
// can be called like this in any file and defaults apply:
$('#foo').skinnify();
// or you can set up your a settings object in a new file and then run the extension
// just make sure you load the skinning js file first!
var data2 = {
primaryThemeColor: "#413098",
primaryBtnBgColor: "#38471A",
primaryBtnBgHoverColor: "#b332e0",
primaryBtnBorderColor: "#2d3300",
primaryBtnFontColor: "#671A33",
primaryBtnFontHoverColor: "#D3D3D3",
}
// new settings
$('#bar').skinnify(data2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">Button foo</div>
<div id="bar">Button bar</div>
I want to get not just the title and the url from my page when using the recomment by email button, but also part of the content.
I have this function:
function emailCurrentPage(){
var doc = window.document;
var requested_div = document.getElementById('single_page');//the div is called single_page
var requested_div_html = requested_div.innerHTML;
window.location.href="mailto:?subject="+document.title+"&body="+escape(window.location.href)+doc.requested_div_html;
}
</script>
The issue is that I get undefined from doc.requested_div_html. Link and title work well.
I think the error is that doc.requested_div_html is undefined, since you stored the HTML of the requested div in requested_div_html, not doc.request_div_html. It's just wrong variables.
I finally solved it like this:
function emailCurrentPage(){
var log = $('#single_page').find('p')[ 0 ];
var requested_div = log.innerHTML;
window.location.href="mailto:?subject="+document.title+"&body="+"URL Articol: "+escape(window.location.href)+" - Incipit articol:"+requested_div;
}
I didn't need the doc element because it is already said window.location
I am having difficulty writing some JavaScript that will cycle through an array of .js files.
I have some JavaScript widgets saved in .js files.
I want to be able to click a "Next" or "Previous" button to cycle through an array of those .js files and have the widgets called and displayed on my HTML page. They can be displayed in an iFrame if that would be a better solution.
I will continue researching until a kind soul helps out. Thanks a bunch in advance!
I have tried:
<script>
function onWindowLoad(){
document.getElementById('js_type').innerHTML = ****.settings.type;
var widget_arr = [1column.js,2column.js,1row.js,modal.js]; //etc..etc..
var currentWidget = 0;
theBtn.onRelease = function(){
currentWidget++;
if(currentWidget == widget_arr.length){
currentWidget=0;
}
var selectedWidget = widget_arr[currentWidget];
//now you have a variable pointing to the next widget..
//what you do with it is up to you.. add the code you need..
}
and this
<SCRIPT LANGUAGE="JavaScript">
<!--
// Use the following variable to specify
// the number of widgets
var NumberOfWidgets = 4
var widget = new Array(NumberOfWidgets)
// Use the following variables to specify the widget names:
widget[0] = "1column.js"
widget[1] = "2column.js"
widget[2] = "1row.js"
widget[3] = "modal.js"
var widgetNumber = 0
function NextWidget()
{
widgetNumber++
if (widgetNumber == NumberOfWidgets)
widgetNumber = 0
document.widgets["VCRWidget"].src = widget[widgetNumber]
}
function PreviousWidget()
{
widgetNumber--
if (widgetNumber < 0)
widgetNumber = NumberOfWidgets - 1
document.widgets["VCRWidget"].src = widget[widgetNumber]
<IMG SRC="modal.js" NAME="VCRWidget">
}
//-->
</SCRIPT>
Code for the previous and next buttons:
<A HREF="javascript:PreviousWidget()">
<IMG SRC="prev.png" BORDER=0></A>
<A HREF="javascript:NextWidget()">
<IMG SRC="next.png" BORDER=0></A>
One idea can be to use the fact thst even a static page can have parameters in the url. You can for example:
create the html page that will be opened in the <iframe> with any js include you need (e.g. jquery)
add to this page a js function that given a widget js filename will create a <script> tag loading the widget creation code.
extract the name of the js file to use to call the function in (2) from document.location.href by looking at the part of the string after ?
in your main page create dinamically the iframe using for example contdiv.innerHTML = "<iframe src=\"widgetpage.html?" + widgetname + ".js\"></iframe>";
With this approach the widgets will be shown in a separate html page without interferring with your main page.