Trying to build HTML elements by code, functions included - javascript

This is my first post, hoping someone can help me:
I wish to build a web project, where all the HTML elements are stored in database and taken from it to build the web page.
i found a problem with the buttons, i cannot find a way to store the function for a button, i´m using Jquery to build the elements, for now the test element definitions are simulated in some arrays i left at the start of my Js file, the only way i can make the buttons to work is if the functions are hardcoded in the Js file, is there a way for me to bring the functions from database too? and having them in an array?
this is my project sample:
HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!--script src="functions.js"></script-->
<script src="system.js"></script>
<!--script src="elements.js"></script-->
</head>
<body>
<body onload="addElements()">
<div id="div1"></div>
</body>
</html>
JS File
/**
VARIABLE DEFINITIONS
THESE ARE SUPPOSED TO COME FROM A DATABASE
STILL UNKNOWN HOW TO BRING THE FUNCTIONS, AS STRING THEY ARE NOT ALLOWED. FOR NOW THERE ARE TEST FUNCTIONS.
**/
let buttonIds = ['btn1', 'btn2'];
let buttonText = ['Show Text', 'Show HTML'];
let buttonFunc = [alert1, alert2];
//let buttonFunc = ['alert("Hi");', 'alert("Hello");'];
let paragraphs = ['This is some <b>bold</b> text in a paragraph.', 'another <b>bold</b> test'];
//HELPER FUNCTIONS
// **** THESE ARE SUPPOSED TO COME FROM DATABASE, UNKNOWN HOW TO DO IT. ****
function alert1() {
alert("Hi");
}
function alert2(){
alert("Hello");
}
function addElements(){
for(var p=0; p<paragraphs.length; p++){ addParagraphs('#div1', paragraphs[p]); }
for(var i=0; i<buttonIds.length; i++) { createButton( '#div1', buttonIds[i] , buttonText[i]); }
}
// ANY ELEMENTS FUNCTION IS DEFINED HERE ONCE THE PAGE IS LOADED.
$(document).ready(function(){
for(var x=0;x<buttonIds.length; x++){ activateButton(buttonIds[x], buttonFunc[x]); }
});
//HELPER FUNCTIONS USED TO BUILD THE HTML ELEMENTS ON THE MAIN PAGE.
function addParagraphs(location, text){
$(location).append('<p id="test">'+text+'</p>');
}
function createButton(location, id, text){
var definition;
definition = "<button id="+id+">"+text+"</button>";
$(location).append(definition);
}
function activateButton(buttonId, functionName){
var composedId = "#"+buttonId;
$(composedId).click(functionName);
}

You can generate Javascript file serverside with all the funcions you need.
Supposing Node.js you can do something like this:
expressApp.get("some.js", (req, res) => {
getDataFromDatabase() // depends on your database
.then(data => {
let body = 'function your_fn () { alert("'+ JSON.stringify(data) +'")}';
res.send(body);
})
});

One approach is use an object to store the functions in javascript and use property names stored in db to associate which function to use for which element.
Without knowing more about your use case it is hard to really help design a proper system to use
Following is a very basic example
// functions stored in js file
const funcs = {
f1: function(e){ console.log('func one called , id = ', this.id)},
f2: function(e){ console.log('func 2 called , id = ', this.id)}
}
// data from database
const elems = [
{id: 1, className: 'one', func:'f1', text:'Item 1'},
{id: 1, className: 'two', func:'f2', text:'Item 2'}
]
elems.forEach(e => {
const $el= $('<div>', {id: e.id, class: e.className, text:e.text, click: funcs[e.func]})
$('body').append($el);
});
div {margin:1em;}
.one {color:red;}
.two {color:green;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<strong>Click on items</strong><br><br>

Related

Text to Html list

I want to make a html which will auto get the information for a *.txt file
something1
something2
something3
and output into this html file
<!DOCTYPE html>
<html>
<head>
<title>List</title>
</head>
<body>
<ul>
#here to output#
</ul>
</body>
</html>
I prefer to use JavaScript. Some help is appreciated.
You have to request the file using AJAX call. Then you need to iterate through each line of response and generate DOM element (li in this case) and input line inside of it. After that insert each li element into your ul list.
You can achieve it using jQuery as you are probably new to JavaScript it's probably the easiest way.
What you need to do is request the file first:
$.ajax('url/to/your/file', {
success: fileRetrieved
});
Now after the file is retrieved jQuery will call fileRetrieved method, so we have to create it:
function fileRetrieved(contents) {
var lines = contents.split('\n');
for(var i = 0; i < lines.length; i += 1) {
createListElement(lines[i]);
}
}
Now for each line from the file function fileRetrieved will call createListElement function passing line of text to it. Now we just need to generate the list element and inject it into DOM.
function createListElement(text) {
var into = $('ul');
var el = $('<li></li>').html(text);
el.appendTo(into);
}
Of course you don't want to retrieve into element each time createListElement is called so just store it somewhere outside the function, it's your call, I'm just giving you the general idea.
Here is an example of the script (without AJAX call of course as we can't simulate it):
var into = $('#result');
function fileRetrieved(contents) {
var lines = contents.split('\n');
for (var i = 0; i < lines.length; i += 1) {
createListElement(lines[i]);
}
}
function createListElement(text) {
var el = $('<li></li>').html(text);
el.appendTo(into);
}
var text = $('#text').html();
fileRetrieved(text);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- This element simulates file contents-->
<pre id="text">
fdsafdsafdsa
fdsafd
safdsaf
dsafdsaf
dsafdsafds
afdsa
</pre>
<div id="result"></div>
Try this
<html>
<head>
<title>List</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<ul id="renderTxt_list">
</ul>
<input type="button" id="lesen" value="Read Data" />
</body>
<script>
$(document).ready(function(){
$("#lesen").click(function() {
$.ajax({
url : "testTxt.txt",
dataType: "text",
success : function (data) {
$html = "";
var lines = data.split("\n");
for (var i = 0, len = lines.length; i < len; i++) {
$html += '<li>'+lines[i]+'</li>';
}
$("body ul").append($html);
}
});
});
});
</script>
</html>
You need to request the file first, and then append it to your chosen place in the document.
You can for example use jQuery's get (or any other function like the native fetch), and then inject it into the ul element:
$.get("*.txt").then(x => $("ul").html("<li>" + x.split('\n').join('</li><li>') + "</li>"))
Let's break this solution by steps:
First, we need to request the external file:
$.get("*.txt")
Read about jQuery's get here. Basicly it will request the file you asked for using network request, and return a promise.
In the Promise's then, we can do stuff with the request's result after it is resolved. In our case we want to first break it by lines:
x.split('\n')
split will return an array that will look like this: ["line 1, "line 2", "line 3"].
JS arrays have the join method, which concat them to string while putting the string you want between the items. So after we do this:
x.split('\n').join('</li><li>')
We only need to add the <li> element to the start and end of the string like this:
"<li>" + x.split('\n').join('</li><li>') + "</li>"
Finally we appent it to your chosen element using jQuery's html.

Get data from Materialize CSS chips

I need to get data from Materialize CSS chips, but I don't know, how.
$('.chips-placeholder').material_chip({
placeholder: 'Stanici přidíte stisknutím klávesy enter',
secondaryPlaceholder: '+Přidat',
});
function Show(){
var data = $('.chips-placeholder').material_chip('data');
document.write(data);
}
<!-- Added external styles and scripts -->
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css">
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- HTML body -->
<div class="chips chips-placeholder"></div>
<button onclick="Show()" type="button">Show</button>
So, to access to the data's chip you just have to do this:
var data = $('#id of your chips div').material_chip('data');
alert(data[0].tag);`
'0' is the index of your data (0, 1, 2 , 3, ...).
'tag' is the chip content. You can also get the id of your data with '.id'.
To get data from Materialize CSS chips, use the below code.
$('#button').click(function(){
alert(JSON.stringify(M.Chips.getInstance($('.chips')).chipsData));
});
They appear to have changed the method available in the latest version.
The documentation suggests that you should be able to access the values as properties of the object, but I’ve spent an hour looking, not getting anywhere.
Until the following happened
$('.chips-placeholder').chips({
placeholder: 'Enter a tag',
secondaryPlaceholder: '+Tag',
onChipAdd: (event, chip) => {
console.log(event[0].M_Chips.chipsData);
},
During the onChipAdd event I was able to access the event. Within this object was an array of tags.
I know this isn't the documented way, however there is only so much time a client will accept when it comes billing and I must move on.
This worked great for me
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.chips');
var instances = M.Chips.init(elems, {
placeholder: "Ajouter des Tags",
secondaryPlaceholder: "+tag",
onChipAdd: chips2Input,
onChipDelete: chips2Input,
Limit: 10,
minLength: 1
});
function chips2Input(){
var instance = M.Chips.getInstance(document.getElementById('chip1')), inpt = document.getElementById('myInputField');
inpt.value = null;
for(var i=0; i<instance.chipsData.length; i++){
if(inpt.value == null)
inpt.value = instance.chipsData[i].tag;
else{
inpt.value += ','+instance.chipsData[i].tag; //csv
}
}
console.log('new value: ', inpt.value);
}
});
</script>

Parse content from a html page

Need to dynamically update contents in a div of main page, based on data fetched from other html page
setInterval( function() {
$.ajax({
type:'GET',
url:"url for status",
success : function(data){
console.log(data);
}
})
},3000);
The content of 'data' printed in developer tool console is:
<html>
<style>
</style>
<head>
</head>
<script>
var conns=[{num:1,
id:1,
Conn:[{type:'ppp',
Enable:1,
ConnectionStatus:'Disconnected',
Name:'CONNECTION_1',
Uptime:0,
ConnectionError:'TIME_OUT',
..............
}]
},
{num:2,
id:2,
Conn:[{type:'ppp',
Enable:1,
ConnectionStatus:'Disconnected',
Name:'CONNECTION_2',
Uptime:0,
ConnectionError:'TIME_OUT',
..............
}]
}]
</script>
</html>
Need to extract the ConnectionStatus, Name and ConnectionError from this content and display it in respective div in main page.
I would recommend using a different transfer type, however, you could use something like this:
function break_out_each_id(){//returns array of indexes where id starts
var i = 0;
id_objs = [];
while data.indexOf('id', i) > -1{
id_objs[i] = data.indexOf('id', i);
i++;
}
return id_objs
}
function find_values(){//pseudo code
use the array of indexes from first index to next index
in that string, do index of each value you are looking for (ConnectionStatus...)
then parse that line after the ':' to get the value.
Do this for each index in indexes array
}
Sorry for the pseudo code, but this post is getting really long. Like I said, it would be MUCH better to just send the response as JSON (even if it is a stringified version of it). In that case you could just do a simple JSON.parse() and you'd be done.

Definition of Function SubmitSurvey have not been found but I defined it

It is literally fifth day I try to solve this.
I try to invoke a method by a button in Razor View, no redirections to other views, just invoke a simple method when button is clicked.
The script looks like:
<script>
function SubmitClick () {
var pid = $(this).data('personid');
var sid = $(this).data('surveyid');
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personid: pid, surveyid: sid }, function (data) {
alert('updated');
});
};
</script>
The button looks like:
<button class='mybutton' type='button' data-personid="#Model.Item1.Id" data-surveyid="#survey.Id" onclick="javascript:SubmitClick()">Click Me</button>
The PersonController method looks like:
public void SubmitSurvey(int personId, int surveyId) {
System.Diagnostics.Debug.WriteLine("UPDATING DATABASE");
}
The full view (this is PartialView):
<script>
function SubmitClick () {
var pid = $(this).data('personid');
var sid = $(this).data('surveyid');
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personid: pid, surveyid: sid }, function (data) {
alert('updated');
});
};
</script>
#using WebApplication2.Models
#model System.Tuple<Person, List<Survey>>
<hr />
<h1>Surveys</h1>
<input type="button" id="Coll" value="Collapse" onclick="javascript:CollapseDiv()" />
#*<p>
Number of Surveys: #Html.DisplayFor(x => Model.Item2.Count)
</p>*#
#{int i = 1;}
#foreach (var survey in Model.Item2) {
using (Html.BeginForm()) {
<h2>Survey #(i)</h2>
<p />
#Html.EditorFor(x => survey.Questions)
<button class='mybutton' type='button' data-personid="#Model.Item1.Id" data-surveyid="#survey.Id" onclick="javascript:SubmitClick()">Click Me</button>
}
i++;
<hr style="background-color:rgb(126, 126, 126);height: 5px" />
}
<hr />
The problem is that when I click the button:
I get runtime error saying that there is no definition of: "SubmitClick".
I don't see any obvious problems in your code, but given that you're handling this in a sub-optimal way, refactoring your code may solve the problem just by improving the setup.
First, don't embed your scripts directly in the view. I understand that you need to include a URL generated via one of the Razor helpers, but what I'm talking about here is using sections so that your scripts get included in a standard location in the document:
So, in your view:
#section Scripts
{
<script>
// your code here
</script>
}
And then in your layout:
<!-- global scripts like jQuery here -->
#RenderSection("Scripts", required: false)
</body>
This ensures that 1) all your JavaScript goes where it should, right before the closing body tag and 2) all your JavaScript gets run after the various global scripts that it will likely depend on (jQuery).
Second, it's usually a bad idea to define things in the global scope, such as you are doing with your SubmitClick function. If another script comes along and defines it's own SubmitClick function in the global scope, then yours gets hosed or vice versa. Instead, you want to use namespaces or closures.
Namespace
var MyNamespace = MyNamespace || {};
MyNamespace.SubmitClick = function () {
...
}
Closure
(function () {
// your code here
})();
Of course, if you use a closure like this, then you SubmitClick function truly won't exist, as it's no longer in the global scope, which brings me to...
Third, don't use the on* HTML attributes. It's far better to bind functionality to elements dynamically, for example:
(function () {
$('.mybutton').on('click', function () {
var pid = $(this).data('personid');
var sid = $(this).data('surveyid');
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personid: pid, surveyid: sid }, function (data) {
alert('updated');
});
});
})();
Now, you've got zero scope pollution and behavior is bound where behavior is defined, instead of tightly-coupling your HTML and JavaScript.

External Javascript File Fetch?

I am currently using this code:
var wordRandomizer = {
run: function (targetElem) {
var markup = this.createMarkup();
targetElem.appendChild(markup);
},
createMarkup: function () {
var that = this;
var frag = document.createDocumentFragment();
this.elem = document.createElement('span');
var button = document.createElement('button');
button.innerText = 'Change Item';
button.addEventListener('click', function () {
that.changeItem();
});
frag.appendChild(this.elem);
frag.appendChild(button);
return frag;
},
changeItem: function () {
var rand = this.getRandInt(1, this.items.length) - 1;
console.log(rand);
this.elem.innerText = this.items[rand];
},
getRandInt: function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
},
items: ['itemA', 'itemB', 'itemC', 'itemD']
};
wordRandomizer.run(document.body);
I code is a button which when pressed grabs one of the items in the list. However, I don't want the items to show on the same page as the generator as people simply look at the source code. How can I make it so once the button is pressed it grabs the random item from another location where people cannot view them all using the source code.
If it helps, you can see the code in action here - http://jsbin.com/ESOdELU/1/edit
I will give you a solution using PHP since it is a free scripting language and is the most likely to be supported by a host or default web server...
For starters, here is the code to include jquery and the basic AJAX script
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/JavaScript">
$(document).ready(function(){
$("#generate").click(function(){
$("#madlibs p").load("script.php");
});
});
</script>
Here is the code for script.php
<?php
header("Cache-Control: no-cache");
// For testing you can use an inline array like the lines below
// Just remove the comment slashes "//" from the beginning of the line
// and comment out the external declarations
//$actors = array('Denzel Washington','Michael J. Fox','Jim Carey','Boris Kodjoe');
//$roles = array('Mental Patient','Homeless Musician','Drag Queen Detective','Tormented Mathematician');
// In production, you would put these in a text file or a database.
// For $actors, put an entry on each line of a text file and save it as 'leads.txt'
// Do the same with a separate file for $roles (roles.txt).
$actors = file("leads.txt");
$roles = file("roles.txt");
// This selects a random element of each array on the fly
echo $prefixes[rand(0,count($actors)-1)] . " stars as a "
. $suffixes[rand(0,count($roles)-1)] . " in the next blockbuster film.";
// Example output:
// Michael J. Fox stars as a Tormented Mathematician in the next blockbuster film.
?>
Put this in the body of your page and be sure to style everything up for display.
<body>
<div id="madlibs"><p> </p></div>
<button id="generate">Surprise Me!</button>
</body>
A couple of notes:
- You can include your basic layout HTML in the script.php file and then would only need the ID of the DIV in which you will be displaying the result $("#madlibs")
You can use any server side language to achieve the same result, just swap out the external file call to the appropriate name and extension (.asp, .cfm, etc.)
Here is a link to the original tutorial that helped me with a similar project:
http://www.sitepoint.com/ajax-jquery/
I hope this helps. Sorry, but I couldn't come up with a purely Java of JavaScript solution on lunch.

Categories

Resources