Building a full stack app which loads a list of songs from an api into a table. How can I make a row's fields editable when the user clicks on the Edit button?
Maybe using a modal would be better?
The API is running on Rails and the table is generated using a template engine Handlebars.
You can do this using JavaScript and uniqueIDs generated most likely from the database.
In the below example, wherever the number "10" is used it is meant to renote the presence of a uniqueID, NOT just as a string 10. AKA, in a working example, is ten would be a uniqueID you have generated from a database, and linked to the code below.
The example:
<table>
<thead>
<th>Song Name</th>
<th>Artist</th>
<th>Genre</th>
<th colspan="2">Actions</th>
</thead>
<tbody>
//Whatever code here should be written in something like PHP which can
return multiple values of the example I've written.
<tr id="tr_10">
<td id="songName_10">Nightcall</td>
<td id="songArtist_10">Kavinsky</td>
<td id="songGenre_10">Synthwave</td>
<td><button onclick="editSongInfo(10)">Edit</button></td>
<td><button>Remove</button></td>
</tr>
</tbody>
<script>
function editSongInfo(uniqueId){
var x = document.getElementById("songName_" + uniqueId);
x.innerHTML = "<input type='text' placeholder='Enter edited song name
here.'>";
x = document.getElementById("songArtist_" + uniqueId);
x.innerHTML = "<input type='text' placeholder='Enter edited song artist
here.'>";
x = document.getElementById("songGenre_" + uniqueId);
x.innerHTML = "<input type='text' placeholder='Enter edited song genre
here.'>";
}
</script>
This will change your text to an input upon click, but it will not submit the response to the database, as that is not the question you asked, and you have not provided any code, or frameworks you wish to use, or even how you access you database.
This answer is the best I can provide with the information you have supplied, which is an image of a table and the tags, "html" and "html-table"
Working example of the above code, here: http://jsfiddle.net/fo2z1vLa/11/
Related
I am taking in an input from a text box in one HTML page and saving it to local storage using this function.
function writeMail(emailInput){
console.log(emailInput);
localStorage.setItem('emailInput',emailInput);
let theEmail = localStorage.getItem('emailInput');
console.log(theEmail);
}
This works fine and I can check the inputs are correct through my console logs.
Yet when I try and get this from local storage to store in my table in my emailList html file, it seems to not work at all.
<body>
email = localstorage["emailInput"];
<table>
<caption> Email list
</caption>
<tr>
<th> Name </th>
<th> Email </th>
</tr>
<tr>
<td>email </td>
</tr>
</table>
</body>
For you to be able to manipulate the contents of HTML, you need to modify the DOM node specifically. In this specific case you should have an id attribute on the <td>and then use the innerHTML property of that node to set the desired value.
i.e.:
<td id="xpto"></td>
then on the code:
let theEmail = localStorage.getItem('emailInput');
document.getElementById("xpto").innerHTML = theEmail;
You should also set that code inside of a function that is called once the document has finished loading, so something like:
JAVASCRIPT:
function go(){
let theEmail = localStorage.getItem('emailInput');
document.getElementById("xpto").innerHTML = theEmail;
}
HTML:
<body onload="go()">
' I am trying to create a form with PERL/CGI, and I would like to process the data introduced in that form within the same CGI file. This is what I have for my code on the HTML5 side….'
<body>
<form action="form.cgi" method="get">
</form>
<h1>Feedback Form</h1>
<p>Please fill out the entire feedback form.</p>
<table>
<tr>
<td><b>To (recipient's e-mail address):</b></td>
</tr>
<tr>
<td><input type = "text" name = "mailTo" size = "40" /></td>
</tr>
<tr>
<td><b>From (your e-mail address):</b></td>
</tr>
<tr>
<td><input type = "text" name = "mailFrom" size = "40" /></td>
</tr>
<tr>
<td><b>Enter a subject:</b></td>
</tr>
<tr>
<td><input type = "text" name = "subjectLine" size = "40" /></td>
</tr>
<tr>
<td><b>Enter your message:</b></td>
</tr>
<tr>
<td><textarea name = "message" rows = "10" cols = "50"></textarea></td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td><input type = "submit" name = "sbutton" value = "Submit" />
<input type = "reset" value = "Reset" /></td>
</tr>
</table>
<br><br><br><br><br>
</div>
</body></html>
PERL/CGI form CODE
#!/usr/bin/perl
use Modern:: Perl;
use Mail::Sendmail;
my $mailFrom = email#email';
my $subjectLine = "Sample Subject:l
my $message = "Sample Message!";
my %mail = ( To => $mailTo,
From => $mailFrom,
Subject => $subjectLine,
Message => $message,
'Content-Type' => 'text/plain'
);
if ( sendmail %mail )
{
print "Sucessfully sent mail to $mailTo. Check you box! \n";
}
else
{
print "Error sending mail: $Mail::Sendmail::error \n";
}
I have spent over a couple of hours trying to figure out this code. Please can anyone help me out. I had made two different files for these two different codes. I feel that I am missing something or if I am missing something small.
Thank you :)
All of your input fields must be between the opening <form> and closing </form> tags.
Also, the form method should be "post", not "get".
The form action you have as form.cgi. Where does this file live on your server? In typical setups, it might be in the cgi-bin directory, in which case you may want to try action="/cgi-bin/form.cgi".
Hope those suggestions help.
You are using a lot of variables that don't have values - $mailTo, $subjectLine, $message. I guess that you're used to PHP where variables like those are filled in automatically for you. That's not the case in Perl. You need to extract the form field data yourself.
As you're writing a CGI program, your easiest solution is probably to use the param() function from the CGI module to do this.
use CGI 'param';
my $subjectLine = param('subjectLine'); # etc...
Also, a CGI program needs to send a "Content-type" header before sending any real output. As you are writing plain text, you should use text/plain. The CGI module also has a header() function that will help you here.
# Load both of the functions you're going to use
use CGI ('header', 'param');
# Run this before any other print statements
print header(-type => 'text/plain');
If you're going to be writing CGI programs, then it will be a good idea to take the time to read the documentation for the CGI module. But I'd also recommend reading CGI::Alternatives as CGI is no longer the best way to write web programs in Perl.
Also, in your HTML, your closing </form> tag should come after all of the form inputs.
It's easy to have a perl CGI form call itself, here's a small example using your HTML code. (By the way, all the form fields have to be enclosed within the <form> tags, not the way yours is. And yes the form method is POST.)
This CGI file has to function differently depending on how it's accessed. First it needs to print out HTML with empty form fields. This is the "$html" variable in the code. Then when it's submitted, it needs to receive the form parameters, and do something with the data. To email it, call the mailForm subroutine. I don't have sendmail on my server, so I just print out the form data in the example. The code below mails it.
The CGI script needs to tell the difference between just being visited as a web page, and being called as a form action. To do this, it checks for a hidden form field called "check." If "check" is defined, that means the form was submitted and there's data to collect and process. If "check" isn't defined, it just prints out the empty form fields.
There are probably more elegant ways to do this, but I just wanted to demonstrate a CGI file processing its own submitted data, in case anyone is interested in the future. Make sure the file has the same name as the form's action. Here's my sample code, form.cgi:
#!/usr/bin/perl
use CGI::Carp qw(fatalsToBrowser set_message warningsToBrowser);
use CGI qw(:standard);
use strict;
use warnings;
print header();
my $cgi = CGI->new();
my $check;
$check = $cgi->param('check') if defined $cgi->param('check');
my $newhtml = '';
if ($check eq "yes") { #collect form data and build email subroutine
my $fromemail = $cgi->param('mailFrom');
my $toemail = $cgi->param('mailTo');
my $subject = $cgi->param('subjectLine');
my $message = $cgi->param('messageBody');
$newhtml = qq{
<html>
<body>
<b>Email sent!</b>
<br>
The from email is from $fromemail<br>
The to email is to $toemail<br>
The subject is $subject<br>
The message is $message<br>
</body>
</html>
};
sub mailForm {
open(MAIL, "|/usr/sbin/sendmail -t");
print MAIL "To: $toemail\n";
print MAIL "From: $fromemail\n";
print MAIL "Subject: $subject\n\n";
print MAIL $message;
close(MAIL);
}
} #end of if check
my $html = qq{
<html>
<body>
<form action="form.cgi" method="POST">
<h1>Feedback Form</h1>
<p>Please fill out the entire feedback form.</p>
<table>
<tr>
<td><b>To (recipient's e-mail address):</b></td>
</tr>
<tr>
<td><input type = "text" name = "mailTo" size = "40" maxlength = "50" /></td>
</tr>
<tr>
<td><b>From (your e-mail address):</b></td>
</tr>
<tr>
<td><input type = "text" name = "mailFrom" size = "40" maxlength = "50" /></td>
</tr>
<tr>
<td><b>Enter a subject:</b></td>
</tr>
<tr>
<td><input type = "text" name = "subjectLine" size = "40" maxlength = "50"></td>
</tr>
<tr>
<td><b>Enter your message:</b></td>
</tr>
<tr>
<td><textarea name = "messageBody" rows = "10" cols = "50" maxlength = "300"></textarea></td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td><input type = "submit" name = "sbutton" value = "Submit" />
<input type = "reset" value = "Reset" />
<input type = "hidden" name = "check" value = "yes">
</td>
</tr>
</table>
</form>
<br>
</body></html>
};
#this prints the regular page if no form is submitted
if (!defined $check) {
print $html;
}
#this mails the form data and prints a confirmation page
else {
print $newhtml;
mailForm();
}
exit 0;
I am rendering my DataTable the angular way, I added a checkbox per row and a select all checkbox at the top. The problem is that for example, I filter the rows using the search box if I check the select all it checks all the rows. What do I do so that when the select all checkbox is clicked, it only checks the visible rows after the filtering.
Html
<table id="tblAvailable" datatable="ng" dt-options="mainCtrl.dtOptions" dt-instance="mainCtrl.dtInstance" dt-column-defs="mainCtrl.dtColumnDefs" class="table table-responsive table-hover">
<thead>
<tr>
<th>Ref. #</th>
<th>Type</th>
<th>Category</th>
<th>Applied Amount</th>
<th>New Amount</th>
<th><input type="checkbox" ng-model="mainCtrl.selectAll" ng-click="mainCtrl.toggleAll(mainCtrl.selectAll)" ng-change="mainCtrl.update()"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="Item in mainCtrl.newLineDetails" ng-if="Item.Amount > 0">
<td>{{Item.Id}}</td>
<td>{{Item.Type.Name}}</td>
<td>{{Item.Category.Name}}</td>
<td>{{Item.Amount | number:2}}</td>
<td><input type="number" ng-disabled="Item.isSelected == false" id="Amount" name="Amount" class="form-control ng-pristine ng-untouched ng-valid ng-not-empty" ng-model="Item.Amount" ng-min="1" ng-max="Item.Amount" ng-required="Item.isSelected == true" ng-change="mainCtrl.updateForFreeUps()"/></td>
<td><input type="checkbox" ng-model="Item.isSelected" ng-change="mainCtrl.toggleOne(Item.Id)"></td>
</tr>
</tbody>
</table>
Ctrl
self.toggleAll = function(selectAll) {
angular.forEach(self.newLineDetails, function (value, index) {
self.newLineDetails[index]["isSelected"] = selectAll;
if (selectAll == false) {
self.newLineDetails[index]["Amount"] = null;
}
})
}
self.toggleOne = function (Id) {
for (var i = 0, len = self.newLineDetails.length; i < len; i++) {
if (self.newLineDetails[i]["Id"] == Id) {
self.newLineDetails[i]["Amount"] = null;
self.selectAll = false;
self.update();
return;
}
}
self.selectAll = true;
}
You must go through the DataTables API. DT remove and inject DOM nodes from a "shadow table" so just manipulating DOM will only have apparently (not real) effect until next redraw. Fortunately you have already implemented a dtInstance.
From 1.10.6 the most convenient way to iterate through rows, columns or cells is the every method. See this plunkr -> http://plnkr.co/edit/NOP5u4PUcwVOBFUtBkBi?p=preview
$scope.$watch('settings.selectAll', function(newVal, oldVal) {
if (newVal == oldVal) return
var api = $scope.dtInstance.DataTable;
api.rows({ search:'applied' }).every(function() {
api.cell({ row:this.index(), column:0 })
.nodes()
.to$()
.find('input')
.prop('checked', $scope.settings.selectAll);
})
$scope.dtInstance.DataTable.draw()
})
Here the checkbox is in column 0; the code can be translated into
cycle through all rows
get the first column
convert to jQuery instance
find the <input>
update the checked status
Some notes about your selectAll checkbox :
best to use an object as ng-model, in the example I have used a settings.selectAll literal
ng-click does not work effectively with checkboxes, if you really want to use a directive, use ng-change only
since you are using a ng-model, you can just $watch that value, calling mainCtrl.toggleAll(mainCtrl.selectAll) is "obscure"
There are many ways for solving this problem:
1) You can write change function for select all checkbox. In that function first you should filter all of your data after that check them.
2) You can copy your main data to another variable (we call it x for now). after that show x in table (not your main resource). when you want to filter the rows using the search box filter main data and past it into the x variable when you want to use it for check or add etc use x variable
Simple question really, but how can I setup the typeahead to work in a table that works off of a different table than my typeahead?
For Example, I have a foreign key in a table and I want to let the users select this key based on the respective NAME value in the foreign key's primary table.
Code Example:
<table class="table table-bordered table-hover table-striped rwd-table" id="page-wrap">
<thead>
<tr>
<th>Primary ID</th>
<th>Foreign Key (As Name)</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="p in PrimaryTable" id="display">
<td data-th="ID">{{p.PrimaryID}}</td>
<td>
<input id="ForeignKeyName"
type="text"
ng-model="p.ForeignKeyID"
uib-typeahead="f.ForeignKeyID as f.ForeignKeyName for f in ForeignKeyTable | filter:$viewValue"
class="form-control">
</td>
</tr>
</tbody>
With this example, I would want the users to see the "Foreign Key (As Name)" As the Name value instead of the ID value. The trick is that I also want the underlying value to be the ID and have it mapped to match the original value, as notified by the ng-model.
UPDATE: Another question I had that was in line with the previous one is how do I setup my ng-model to show the ForeignKeyTable.ForeignKeyName in place of the PrimaryTable.ForeignKeyID?
This would be similar ( I imagine) to how the uib-typeahead matches the ForeignKeyTable.ForeignKeyID and ForeignKeyTable.ForeignKeyName but with the two seperate tables?
What I would desire is to be able to put ng-model: PrimaryTable.ForeignKeyID as ForeignKeyTable.ForeignKeyName
First thing would be updating PrimaryKeyTable rows every time user selects value in typeahead. You'll have to catch selected item and manually assign its ForeignKeyId value to the row of PrimaryTable.
The way to do it is to add typeahead-on-select directive to your typeahead and bind it to the function that assigns the values for you.
It would look like this:
HTML
<tr ng-repeat="p in PrimaryTable" id="display">
<td data-th="ID">{{p.PrimaryID}}</td>
<td>
<input id="ForeignKeyName"
type="text"
ng-model="selectedItem" <!-- could be anything really for we will not use it here -->
uib-typeahead="f.ForeignKeyID as f.ForeignKeyName for f in ForeignKeyTable | filter:$viewValue"
typeahead-on-select="onSelect($item, $model, $label, p)"
class="form-control">
</td>
</tr>
Inside your controller
$scope.onSelect = function($item, $model, $label, primaryKeyTableRow) {
primaryKeyTableRow.ForeignKeyId = $item.ForeignKeyId;
}
Next step is to display name property value of ForeignKeyTable row that corresponds to ForeignKeyId from PrimaryKeyTable in each row. Since we have to filter ForeignKeyTable to find suitable item it would be a good idea to put that logic inside the controller. For there are multiple rows in which we want to display corresponding name, we'll have to filter the ForeignKeyTable for each row separately. This is where ng-controller for ng-repeat comes in handy. What we'll do is bind new controller for each table row generated by ng-repeat and put some logic inside that controller. In HTML it would look like this:
<tr ng-repeat="p in primaryKeyTable" ng-controller="itemController">
<!-- ... -->
</tr>
And we'll have to define new controller in JS file:
app.controller('itemController', function() {
// ...
});
Now we can have separate logic for each row in the table. So that's a place to filter ForeignKeyTable to find corresponding item and display it's name.
Since whole code is kind of big I've put it in the plunker:
http://plnkr.co/edit/xccgnpxoPHg6vhXWPwZn?p=preview
See what you can do with it.
I’m quite new in html and have just very very basic knowledge of it. I’m trying to prepare a small demo for my department on how the visuals for a project should work.
What I basically want to do is populate a sentence depending on what is clicked on a table. So far I unfortunately was just able to do the resource part but not implement the populating and clicking functionality perhaps someone can help.
The resource data for the sentence to be populated is:
<li>Stage 2 phrase: <br/> “<b>FROM</b> <font color="'#043345">< City 1 ></font> <b>TO</b> <font color="'#043345">< City 2 ></font> <b>VIA</b> <font color="'#043345">< City 3 ></font>”<br/><br/>
The resource data for the table is:
<br/><table border="1" style="width:100%"><tr>
<td>Chicago</td>
<td>Istanbul</td>
<td>Budapest</td>
</tr>
<tr>
<td>Copenhagen</td>
<td>Lisbon</td>
<td>Sydney</td>
</tr>
<tr>
<td>Washington</td>
<td>Singapore</td>
<td>Barcelona</td>
</tr>
<tr>
<td>Helsinki</td>
<td> Next </td>
<td> </td>
</tr>
</table><br/><br/>
What I want to do is make the city names as buttons in the table “clickcable” and after clicking make the city button remain in a specific color depending on if it was clicked first, second or third for example:
First city clicked will be green
Second city clicked will be yellow
Third city clicked will be red
When I click the first city the first placeholder (city 1) in the sentence should be populated with the first clicked city.
The next button in the table should clear all 3 cities clicked and give the option to restart once again. Thanks for your time! Cheers
Is this something you looking for ?
var cityIter = 0;
var buttons = document.getElementsByTagName('button');
function clickCity(n) {
switch(cityIter){
case 0:
document.getElementById(cityIter).style.backgroundColor = 'green';
break;
case 1:
document.getElementById(cityIter).style.backgroundColor = 'yellow';
break;
case 2:
document.getElementById(cityIter).style.backgroundColor = 'red';
break;
}
document.getElementById(cityIter).value = buttons[n].innerHTML;
cityIter+=1;
}
Here
Its rather simple answer but still hope I help you :)