I have the following controller:
import logging
from pylons import request, response, session, tmpl_context as c, url
from pylons.controllers.util import abort, redirect
from webhelpers.html.tags import HTML
from improve.lib.base import BaseController, render
from improve import model
import improve.model.meta as meta
import improve.lib.helpers as h
log = logging.getLogger(__name__)
class AlarmsController(BaseController):
def list(self):
c.alarms = meta.Session.query(model.Alarms).all()
return render('../public/listalarms_table.html')
rendered by this template (listalarms_table.html):
...
<div id="markup">
<table id="alarms">
<thead>
<tr>
<th>Id</th>
<th>Severity</th>
<th>Node</th>
<th>Count</th>
<th>Last Alarm</th>
<th>Log Msg</th>
<th>AckUser</th>
</tr>
</thead>
<tbody>
% for alarms in c.alarms:
<tr>
<td>${alarms.alarmid.__repr__()|n}</td>
<td>${alarms.severity.__repr__()|n}</td>
<td>${alarms.nodeid.__repr__()|n}</td>
<td>${alarms.counter.__repr__()|n}</td>
<td>${alarms.lasteventtime.__repr__()|n}</td>
<td>${alarms.logmsg.__repr__()|n}</td>
<td>${alarms.alarmackuser.__repr__()|n}</td>
</tr>
% endfor
</tbody>
</table>
</div>
<script type="text/javascript">
YAHOO.util.Event.addListener(window, "load", function() {
YAHOO.example.EnhanceFromMarkup = new function() {
var myColumnDefs = [
{key:"id",label:"Id", sortable:true},
{key:"severity",label:"Severity", sortable:true}
{key:"node",label:"Node", sortable:true}
{key:"count",label:"Count",formatter:YAHOO.widget.DataTable.formatNumber,sortable:true},
{key:"lastalarm",label:"LastAlarm",formatter:YAHOO.widget.DataTable.formatCurrency,sortable:true},
{key:"logmsg",label:"Log Msg"}
];
this.myDataSource = new YAHOO.util.DataSource(YAHOO.util.Dom.get("alarms"));
this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
this.myDataSource.responseSchema = {
fields: [{key:"id"},
{key:"severity"},
{key:"node"},
{key:"count", parser:"number"},
{key:"lastalarm", parser:"date"} // point to a custom parser
]
};
this.myDataTable = new YAHOO.widget.DataTable("markup", myColumnDefs, this.myDataSource,
{caption:"Example: Progressively Enhanced Table from Markup",
sortedBy:{key:"id",dir:"asc"}}
);
};
});
The problem:
If I call it using http://myserver:port/listalarms_table.html , I see the correct formating of the YUI table but instead of the data I get the alarms.alarmid.repr()|n instead of the real data
If i call it http://myserver:port/alarms/list I get the data correctly but I loose the YUI format...
How can i get the data with the correct YUI layout?
Thx
Related
I am trying to develop a simple crud app using MEAN stack, but when trying to post form value angular service is not making post request. get request works perfectly but post not. i am using morgan to see the requests made to the nodejs server and it is not receiving the post request and all seems to be the same way that in the angular docs. I imported HttpClient modules.
empleados.component.html
<form [formGroup]="nuevoEmpleado" (submit)="addEmpleado()">
<label>
Nombre:
<input type="text" formControlName="nombre">
</label>
<label>
Apellido:
<input type="text" formControlName="apellido">
</label>
<label>
Cargo:
<input type="text" formControlName="cargo">
</label>
<button class="btn btn-primary" type="submit">Agregar Nuevo Empleado</button>
</form>
{{ nuevoEmpleado.value | json }}
<div class="main-container">
<table class="table table-dark">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Nombre</th>
<th scope="col">Apellido</th>
<th scope="col">Cargo</th>
</tr>
</thead>
<tbody>
<tr *ngFor = "let empleado of listaEmpleados">
<th>{{ empleado.index }}</th>
<td>{{ empleado.nombre }}</td>
<td>{{ empleado.apellido}}</td>
<td>{{ empleado.cargo }}</td>
</tr>
</tbody>
</table>
</div>
empleados.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup , FormControl } from '#angular/forms';
import { EmpleadosService } from './empleados.service'
import { Empleado } from '../../clases/empleado'
#Component({
selector: 'app-empleados',
templateUrl: './empleados.component.html',
styleUrls: ['./empleados.component.css']
})
export class EmpleadosComponent implements OnInit {
listaEmpleados: Empleado[];
nuevoEmpleado = new FormGroup({
nombre: new FormControl(''),
apellido: new FormControl(''),
cargo: new FormControl('')
});
constructor(private empleadosService: EmpleadosService) { }
getEmpleados(){
this.empleadosService.getEmpleados().subscribe(empleados => this.listaEmpleados = empleados);
}
addEmpleado(){
this.empleadosService.addEmpleado(this.nuevoEmpleado.value);
}
ngOnInit(): void {
this.getEmpleados();
this.addEmpleado();
}
}
empleados.service.ts
import { Injectable } from '#angular/core';
import { HttpClient , HttpErrorResponse } from '#angular/common/http';
import { Observable } from 'rxjs';
import { Empleado } from '../../clases/empleado'
#Injectable({
providedIn: 'root'
})
export class EmpleadosService {
//url = 'assets/config.json'
url = 'http://localhost:3000'
constructor(private http: HttpClient) { }
getEmpleados():Observable<Empleado[]>{
return this.http.get<Empleado[]>(this.url);
}
addEmpleado(nuevoEmpleado: Empleado){
console.log(nuevoEmpleado);
return this.http.post<Empleado>(this.url , nuevoEmpleado)
}
}
Expanding on the comment made by R. Richards, without a subscription on the post call the Observerable never fires.
An Observerable is simply a function definition (sort of), it requires a subscription to it to actually get the call to run.
An observable itself is just a definition of a way to handle a stream of values. We can think of it as something close to a function. Creating an observable is somewhat similar to declaring a function, the function itself is just a declaration. Calling the function is something entirely different, as defining a function does not execute its code.
We need to call the function in order for something to happen, and that is also the case with an Observable: we need to subscribe to it in order for it to work!
Taken from 3 common Angular Rxjs Pitfalls
Look at the examples on that link to see what you're missing.
Observables are lazy, untill you subscribe them they wont be fullfilled where in case of promises this can work.
So you will need to subscribe to your post call observable as you have done in get api call.
You must subscribe, since when making an http call that returns an observable, remember that observables are lazy by nature.
I have configured a react website to receive json data and store it into an array in the format depicted in the attached image. How would I go about displaying this information in a table format?json data stored in array
If you don't want to use property names, you could do something like that :
import React, { Component } from "react";
import { render } from "react-dom";
const App = () => {
const data = [
{ id: 0, value: "item 1" },
{ id: 1, value: "item 2" },
{ id: 2, value: "item 3" }
];
const keys = Object.keys(data[0]);
return (
<div>
<table>
<thead>
{keys.map(key => {
return (
<th>
<td>{key}</td>
</th>
);
})}
</thead>
<tbody>
{data.map((item, index) => {
return (
<tr>
{keys.map(key => (
<td>{item[key]}</td>
))}
</tr>
);
})}
</tbody>
</table>
</div>
);
};
render(<App />, document.getElementById("root"));
Note that all of your items need to have the same properties (here 'id' and 'value') for this to work.
Here is the repro on stackblitz
If you need something better then you should look for a package made for this, there's plenty on internet.
I am more familiar with NodeJs than react. I have build a react component that searches for user input and provides the output in a table format based on the value that the user has typed into the search input form. This is working as I want and the code for the module is below:
import React, { Component } from 'react';
import axios from 'axios';
import Suggestions from './Suggestions';
// API url
const API_URL = 'http://localhost:3000/api/file_infos'
class Search extends Component {
state = {
query: '',
results: []
}
getCount = () => {
axios.get(`${API_URL}count?filter[where][id][regexp]=/${this.state.query}/i`)
.then(count => {
this.setState({
results: count.data
})
})
}
// query loop back API for matching queries base on text input
getInfo = () => {
axios.get(`${API_URL}?filter[where][id][regexp]=/${this.state.query}/i&filter[limit]=20`)
.then(response => {
this.setState({
results: response.data
})
})
}
// check to see if input on the search bar has changed and update the search query accordingly
handleInputChange = () => {
this.setState({
query: this.search.value
}, () => {
if (this.state.query && this.state.query.length > 1) {
if (this.state.query) {
this.getInfo()
}
} else if (!this.state.query) {
}
})
}
// render form and pass results back to the home component
render() {
return (
<div>
<form>
<input
placeholder="Search for..."
ref={input => this.search = input}
onChange={this.handleInputChange}
/>
</form>
<Suggestions results={this.state.results} />
</div>
)
}
}
export default Search
The second module is the suggestions module that displays the output in the table format.
The next portion of the app I am building will open a file based on the table row that the user selected. I want that table data returned to a function so that I can make an http post request to my API that will in turn open the file using a NodeJS module.
I want the suggestions component to return the value of the data items in the table cells so that the data can be used to send to the API in order to open my files. The code I have come up with so far is only returning an undefined error.
Below is what I currently have:
import React from 'react';
// return results in a table format based on the text input entered
const Suggestions = (props) => {
const state = {
results: []
}
const handleFormOpen = () => {
this.setState({
results: this.results.value
},
console.log(this.state.results)
)
}
const options = props.results.map(r => (
<tr key={r.id} ref={tr => this.results = tr} onClick={handleFormOpen.bind(this)}>
<td>{r.id}</td>
<td>{r.OriginalPath}</td>
<td>{r.CreateDate}</td>
<td>{r.AccessDate}</td>
<td>{r.WriteDate}</td>
<td><i className="fas fa-book-open"></i></td>
</tr>
))
return <table className="striped responsive-table">
<thead>
<tr>
<th>File Name</th>
<th>Parent Directory</th>
<th>Creation Date</th>
<th>Access Date</th>
<th>Write Date</th>
<th>Open File</th>
</tr>
</thead>
<tbody>
{options}
</tbody>
</table>
}
export default Suggestions;
I am really unsure at this point if I am trying to tackle this issue in the correct way. I am thinking that maybe the suggestions component may need to be turned into a full class extending component but I am fairly lost at this point. Can someone please kindly point out my folly and get me going in the right direction?
UPDATE
As requested in the comments here is the error log from my browser:
Suggestions.js:10 Uncaught TypeError: Cannot read property 'results' of undefined
at Object.handleFormOpen (Suggestions.js:10)
at HTMLUnknownElement.callCallback (react-dom.development.js:145)
at Object.invokeGuardedCallbackDev (react-dom.development.js:195)
at invokeGuardedCallback (react-dom.development.js:248)
at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:262)
at executeDispatch (react-dom.development.js:593)
at executeDispatchesInOrder (react-dom.development.js:615)
at executeDispatchesAndRelease (react-dom.development.js:713)
at executeDispatchesAndReleaseTopLevel (react-dom.development.js:724)
at forEachAccumulated (react-dom.development.js:694)
at runEventsInBatch (react-dom.development.js:855)
at runExtractedEventsInBatch (react-dom.development.js:864)
at handleTopLevel (react-dom.development.js:4857)
at batchedUpdates$1 (react-dom.development.js:17498)
at batchedUpdates (react-dom.development.js:2189)
at dispatchEvent (react-dom.development.js:4936)
at interactiveUpdates$1 (react-dom.development.js:17553)
at interactiveUpdates (react-dom.development.js:2208)
at dispatchInteractiveEvent (react-dom.development.js:4913)
First thing Since your Suggestions component plays with state, I would recommend you to go with statefull component.
Stateless component is meant for getting props and returning jsx elements, there wont be any state mutations in stateless component. This is called pure function in javascript. Hope this makes clear.
Also since you declared handleFormOpen as an arrow function you no need to do binding. binding takes care automatically by arrow function. If you don't want to use arrow function and you want to bind it then do the binding always in constructor only but don't do binding anywhere in the component like you did in map.
PFB corrected Suggestions component code
import React, { Component } from 'react';
// return results in a table format based on the text input entered
export default class Suggestions extends Component {
constructor(props){
super(props);
this.state = {
results: [],
value: ""
}
}
handleFormOpen = (path, id) => {
console.log("id", id, path);//like wise pass value to this function in .map and get the value here
this.setState({
value: id
});
}
render(){
const { results } = this.props;
return (<div>
<table className="striped responsive-table">
<thead>
<tr>
<th>File Name</th>
<th>Parent Directory</th>
<th>Creation Date</th>
<th>Access Date</th>
<th>Write Date</th>
<th>Open File</th>
</tr>
</thead>
<tbody>
{Array.isArray(results) && results.length > 0 && results.map(r => (
<tr key={r.id} ref={tr => this.results = tr} onClick={() => this.handleFormOpen(r.OriginalPath, r.id)}>
<td>{r.id}</td>
<td>{r.OriginalPath}</td>
<td>{r.CreateDate}</td>
<td>{r.AccessDate}</td>
<td>{r.WriteDate}</td>
<td><i className="fas fa-book-open"></i></td>
</tr>
))}
</tbody>
</table>
</div>)
}
}
export default Suggestions;
You are using states in Functional Component, You need to use React Component
import React from 'react';
// return results in a table format based on the text input entered
class Suggestions extends React.Component {
constructor(props) {
super(props);
this.state = {
results: [],
}
}
handleFormOpen = () => {
this.setState({
results: this.results.value
},
console.log(this.state.results)
)
}
render () {
const options = this.props.results.map(r => (
<tr key={r.id} ref={tr => this.results = tr} onClick={handleFormOpen.bind(this)}>
<td>{r.id}</td>
<td>{r.OriginalPath}</td>
<td>{r.CreateDate}</td>
<td>{r.AccessDate}</td>
<td>{r.WriteDate}</td>
<td><i className="fas fa-book-open"></i></td>
</tr>
))
return (
<table className="striped responsive-table">
<thead>
<tr>
<th>File Name</th>
<th>Parent Directory</th>
<th>Creation Date</th>
<th>Access Date</th>
<th>Write Date</th>
<th>Open File</th>
</tr>
</thead>
<tbody>
{options}
</tbody>
</table>
)
}
}
export default Suggestions;
For my class I have to design an app that says at the top of the page whether an incoming request is GET or POST, then has to print a table that shows all parameter names and values that were sent in the URL query string, and the property names and values that were received in the request body.
So far I have been able to get my localhost:port to work, it correctly shows whether a request is GET or POST. But when I go to the subpage that is supposed to display the tables, I get a 404 instead.
Here is the render page that I think is causing the problem:
function runQ(req) {
console.log(req.qParams);
console.log(req.body);
var context = {};
context.queryParams = [];
context.bodyParams = [];
context.queryCount = 0;
context.bodyCount = 0;
for( var p in req.qParams) {
context.queryCount++;
context.queryParams.push({'name': p, 'value': req.qParams[p] });
}
for( var p in req.body) {
context.bodyCount++;
context.bodyParams.push({'name': p, 'value': req.body[p] });
}
context.methodType = req.method;
return context;
}
app.get('/request', function(req, res) {
res.render('request', runQ(req));
});
app.post('/request', function(req, res) {
res.render('request', runQ(req));
});
I have a request.handlebar saved in my ubuntu/getpost/views folder along with the 404 and 500 handlebars.
The command I use for testing is:
$ curl --data "a=1&b=2&c=3" localhost:port
I replaced the localhost:port with an actual IP and port address when I have node running.
My console returns this on the tab that is running node:
undefined
{ a: '1', b: '2', c: '3' }
And this on the tab where I typed the cURL command:
<!doctype html>
<html>
<head>
<title>Demo Page</title>
</head>
<body>
<h1>POST Request Received</h1>
<table>
<caption><p>Request Body Table</p></caption>
<thead>
<tr>
<th>Property Names</th>
<th>Values</th>
</tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td>1</td>
</tr>
<tr>
<td>b</td>
<td>2</td>
</tr>
<tr>
<td>c</td>
<td>3</td>
</tr>
</tbody>
</table>
</body>
So everything seems to be working from the console but when I try to access localhost:port/request, I go to the 404 error instead of a page that displays the tables.
Can anyone tell me what I'm doing wrong? Thank you all for your time.
I have a view with a table of products that can be added to a shopping cart. Each row has a DropDownList with allowed quantities that can be ordered along with a button to add to cart. Everything is populating and displaying properly. I know how to pass the item ID in the ActionLink but how can I get the value of the DownDownList associated with the table row of the ActionLink that was clicked?
I am guessing possibly using JQuery that fires when the ActionLink is clicked?
I also thought of making every row a form but that seems overkill.
Is there an easy MVC way to do this?
In prepping more info for a proper question and went ahead and solved it. Thank you Stephen for the nudge and info.
I tried putting a Html.BeginForm around each <tr> tag in the details section. This did indeed work for me. I was able to easily get the unique form info to POST for each individual row. However, when I would enable JQuery DataTables the submit would break. DataTables must be capturing the submit or click somehow. Haven't figured that out but it made me try JQuery which seems a much better way to do it.
Here is how I construct the table data row:
#foreach (var item in Model)
{
<tr>
<td>
<img src="#item.GetFrontImage()" width="100" />
</td>
<td>
<strong>#Html.DisplayFor(modelItem => item.DisplayName)</strong>
</td>
<td>
#Html.DisplayFor(modelItem => item.CustomerSKU)
</td>
<td>
#Html.DropDownList("OrderQty", item.GetAllowedOrderQuantities(), htmlAttributes: new { #class = "form-control" })
</td>
<td>
<a class="btn btn-default pull-right" data-id="#item.ID">Add to Cart</a>
</td>
</tr>
}
This creates a select with id of OrderQty and I embedded the item ID in data-id attribute of the link. I then used this JQuery to capture the info and POST it to my controller. Just have a test div displaying the results in this example:
// Add to Cart click
$('table .btn').click(function () {
// Gather data for post
var dataAddToCard = {
ID: $(this).data('id'), // Get data-id attribute (Item ID)
Quantity: $(this).parent().parent().find('select').val() // Get selected value of dropdown in same row as button that was clicked
}
// POST data to controller
$.ajax({
url: '#Url.Action("AddToCart","Shopping")',
type: 'POST',
data: JSON.stringify(dataAddToCard),
contentType: 'application/json',
success: function (data) { $('#Result').html(data.ID + ' ' + data.Quantity); }
})
});
The JQuery function receives the reference to the link being clicked so I can extract the Item ID from the data-id attribute. I can then get a reference to the dropdown (select) that is in the same row by using .parent.parent (gets me to the <tr> tag) and then just finding the next 'select' tag. Probably pretty obvious to a lot of you.
This works great for my purposes. I can also update other elements with data returned from the POST.
Thank you
Karl
for the table in html:
<div class="table-responsive">
<table id="employeeTable"class="table table-bordered">
<thead>
<tr>
<th class="text-center">ُُُEmpId</th>
<th class="text-center">Name</th>
<th class="text-center">Absense State</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>#item.Name</td>
<td class="text-center">#Html.DropDownList("DDL_AbsentStatus", new SelectList(ViewBag.statusList, "Id", "Name"), new { #class = "form-control text-center" })</td>
</tr>
}
</tbody>
</table>
</div>
in javascript to get the selected value:
//Collect Date For Pass To Controller
$("#btn_save").click(function (e) {
e.preventDefault();
if ($.trim($("#datepicker1").val()) == "") {
alert("ادخل تاريخ يوم صحيح!")
return;
}
var employeesArr = [];
employeesArr.length = 0;
$.each($("#employeeTable tbody tr"), function () {
employeesArr.push({
EmpId: $(this).find('td:eq(0)').html(),
EntryDate: $.trim($("#datepicker1").val()),
StatusId: $(this).find('#DDL_AbsentStatus').val()
});
});
$.ajax({
url: '/Home/SaveAbsentState',
type: "POST",
dataType: "json",
data: JSON.stringify(employeesArr),
contentType: 'application/json; charset=utf-8',
success: function (result) {
alert(result);
emptyItems();
},
error: function (err) {
alert(err.statusText);
}
});
})