I am trying to make a angular work with a REST service and $resource.
it works to GET the datas from JSON, but when updating whith $save() or a custom method called $rec(), i have an error in the console saying : TypeError: Object #<c> has no method 'push'. Switching isArray to true or false, didn't change anything.
i made a plunker : http://plnkr.co/edit/fS2bjRKPgUulTbTxgg2j
the error is visible when you make it run on your own server.
the html:
<div ng-controller="TestCtrl">
<div ng-repeat="obj in objs">
<div>
<h3>{{obj.name}}</h3>
<h3>{{obj.age}}</h3>
<input type="text" ng-model="obj.name" /><br />
<input type="text" ng-model="obj.age" /><br />
<button ng-click="save(obj)">Save</button>
</div>
</div>
</div>
and the javascript:
'use strict';
angular.module('TestApp', ['TestApp.services', 'TestApp.controllers']);
angular.module('TestApp.services', ['ngResource']).
factory('Obj', function($resource){
return $resource('datas.json', {}, { 'rec': {method: 'POST', isArray: true } });
});
angular.module('TestApp.controllers', []).
controller('TestCtrl', ['$scope', 'Obj', function($scope, Obj) {
$scope.objs = Obj.query();
$scope.save = function(obj) {
obj.$save();
console.log(obj);
}
}]);
do you know where the error comes from ?
I have copied your plnkr to my dev machine, set up a sinatra site as below but I still do not see this error. the client posts a JSON string like {"name"=>"louise", "age"=>"32"} when I click on a blue button, and everything seems fine. Are you handling the POST appropriately?
here is my server code:
app.ru:
# -*- coding:utf-8; mode:ruby; -*-
require 'json'
require 'multi_json'
require 'sinatra/base'
require 'sinatra/json'
class App < Sinatra::Base
helpers Sinatra::JSON
get '/datas.json' do
json([
{"name" => "louise", "age" => "32"},
{"name" => "jeanne", "age" => "25"},
{"name" => "renée", "age" => "21"},
{"name" => "fernande", "age" => "28"}
])
end
post '/datas.json' do
data = JSON.parse request.body.read.to_s
200
end
end
config.ru:
# -*- coding:utf-8; mode:ruby; -*-
require './app.rb'
run App
Related
JS 13 and inside my ReadMoreButton client component i push my article data using useRouter hook of NEXT.
Not i can not use useRouter hook inside NEXT.JS server component so here i fetch searchParams and fetch that data.
here problem is before rendering i am checking if searchParams are defined or not not if i check in development everything work fine it render data but in production mode it show page not found error even if data is correctly send.
when i run next build it give me following output Output
and i am running side in production mode using next start and it show page not found when i do /article?serchParamsData.
You can check my whole code here : https://github.com/ssiwach8888/Next.JS-News-App
i also deploy production build on Vercel but it also show same error.
I am using NEXT.JS 13 with typescript
# ReadMoreButton.tsx "First Control goes here."
"use client";
type Props = {
article: NewsData;
};
import { useRouter } from "next/navigation";
//For navigate to SSC
const ReadMoreButton = ({ article }: Props) => {
const router = useRouter();
const handleClick = () => {
const queryString = Object.entries(article)
.map(([key, value]) => `${key}=${value}`)
.join("&");
const url = `/article?${queryString}`;
router.push(url);
};
return (
<button
className="bg-orange-400 h-10 rounded-b-lg dark:text-gray-900 hover:bg-orange-500"
onClick={handleClick}
>
Read More
</button>
);
};
export default ReadMoreButton;
# Article.tsx "Then we navigate to this page."
type Props = {
searchParams?: NewsData;
};
import { notFound } from "next/navigation";
import LiveTimestamp from "../Components/LiveTimestamp";
import Link from "next/link";
const ArticlePage = ({ searchParams }: Props) => {
if (
(searchParams && Object.entries(searchParams).length === 0) ||
!searchParams
) {
return notFound();
}
const article: NewsData = searchParams;
return (
<article className="mt-6">
<section className="flex flex-col lg:flex-row pb-24 px-0 lg:px-10">
<img
src={article.image === "null" ? "/no-image.jpeg" : article.image}
alt={article.title}
className="h-50 max-w-md mx-auto md:max-w-lg lg:max-w-xl object-contain rounded-lg shadow-md"
/>
<div className="px-8">
<Link legacyBehavior href={article.url || ""}>
<a target="_blank">
<h1 className="headerTitle hover:underline cursor-pointer px-0 pb-2">
{article.title}
</h1>
</a>
</Link>
<div className="flex divide-x-2 space-x-4">
<h2 className="font-bold">
By: {article.author !== "null" ? article.author : "Unknown"}
</h2>
<h2 className="font-bold pl-4">Source: {article.source}</h2>
<p className="pl-4">
<LiveTimestamp
time={
article.published_at === "null" ? "" : article.published_at
}
/>
</p>
</div>
<p className="pt-4 text-lg">{article.description}</p>
</div>
</section>
</article>
);
};
export default ArticlePage;
You just need to put the article page in [bracket] to make it dynamic so next js can fetch all pages otherwise it would display blank----
change article folder to [article]
more reference https://nextjs.org/docs/routing/dynamic-routes
I'm trying to display information coming from a rest API with Vue.js
In a component I want to display users...
<template>
<div>
<h1>User Manager</h1>
<p>
{{ users }}
</p>
</div>
</template>
In the script part :
<script>
import {AxiosInstance as axios} from "axios";
export default {
name: "User",
data(){
return{
users: null
}
},
methods: {
getUsers(){
axios.get("http://localhost:4000/api/users").then(response => {
console.log(response);
this.users = response.data;
});
}
},
mounted(){
this.getUsers();
}
}
</script>
<style scoped></style>
I obtain unfortunatelly an error message such as :
Error in mounted hook: "TypeError: Cannot read property 'get' of undefined"
TypeError: Cannot read property 'get' of undefined...
I need help with searching the meteor collection with more parameters.
I am using search query and filters to see certain objects from a collection. The problem is that I want client to load whole collection and then reactively change what the user sees, but only changing the subscribe, not calling server again. Thill now search query + one filter is working okay, but only if I call server every time something changes. Now in my code below you can see that I am doing it with if else elements, but that is not a good way. Any suggestion will help. Thank you.
Template.jobs.onCreated( function showOnCreate() {
Meteor.subscribe('Jobs');
this.searchQuery = new ReactiveVar('');
this.remoteQuery = new ReactiveVar(false);
this.typeQuery = new ReactiveVar(false);
});
Template.jobs.helpers({
job: () => {
query = Template.instance().searchQuery.get();
remoteQuery = Template.instance().remoteQuery.get();
typeQuery = Template.instance().typeQuery.get();
let regex = new RegExp( query, 'i' );
// **************************
// the problem starts here
// **************************
if (Router.current().params.slug) {
const companyJobs = Company.findOne({slug: Router.current().params.slug}).jobs;
if ( companyJobs !== undefined) {
return Meteor.subscribe('Jobs', {'_id': { '$in': companyJobs }});
}
return false
} else if (Router.current().params.slug === undefined && remoteQuery === true ) {
return Job.find({ $or: [ { Name: regex }, { Description: regex }, ] , Remote: true, positionType: [],});
} else if (typeQuery = '') {
return Job.find({ $or: [ { Name: regex }, { Description: regex }, ] , positionType: typeQuery, });
},
// -------*****************************
employer: () => {
if (Router.current().params.slug === undefined) {
Meteor.subscribe('Companies');
return 'Poslodavac: ' + Company.findOne({_id: Template.currentData().CompanyId}).Name;
}
return false
},
jobUrl: () => {
Meteor.subscribe('Companies');
companySlug = Company.findOne({_id: Template.currentData().CompanyId}).slug;
return ('/company/' + companySlug + '/job/' );
}
});
Template.jobs.events({
'click .positionType': (event, templateInstance) => {
if (Template.instance().remoteQuery.get().lenght > 1){
Template.instance().typeQuery.set(Template.instance().remoteQuery.get().push(event.target.value));
console.log(Template.instance().remoteQuery.get())
} else {
console.log(Template.instance().remoteQuery.get())
console.log('ggggggg')
Template.instance().typeQuery.set(event.target.value);
}
},
'click #remoteFriendly': (event, templateInstance) => {
Template.instance().remoteQuery.set(!Template.instance().remoteQuery.get());
},
});
Html tempalte with filters:
<template name="jobs" >
<div>
<p>Filteri:</p>
<span>
<input type="checkbox" id="remoteFriendly" name="remote"> <span for="remoteFriendly"> Remote friendly? </span>
</span>
<span>
<p>Tip pozicije:</p>
<input type="checkbox" class="positionType" id="1" value="Programiranje" > <span for="1"> Programiranje </span>
<input type="checkbox" class="positionType" id="2" value="Dizajn" > <span for="2"> Dizajn </span>
<input type="checkbox" class="positionType" id="3" value="Marketing" > <span for="3"> Marketing </span>
<input type="checkbox" class="positionType" id="4" value="Ostalo" > <span for="4"> Ostalo </span>
</span>
</div>
{{#each job}}
<div style="border: 0.1rem solid black; margin: 1cm; padding: 5px; max-width: 420px;" > <!-- OVO JE PRIVREMENI STIL, OBRISATI-->
<p> Posao: {{Name}} <br> Opis: {{Description}}</p>
<p> {{employer}} </p>
<p>Remote friendly?: {{Remote}}</p>
<p>Tip pozicije: {{positionType}}</p>
<p> Saznajte vise OVDE</p>
</div>
{{/each}}
<p id="nesto"></p>
</template>
Welcome to SO!
You seem to be confused between Pub/Sub and Collection.find.
You should first realize that the 2 are different mechanisms, which provide different functionalities.
Pub/Sub indeed sends data from your Server into your Client's Minimongo database. But this data is not displayed yet.
Collection.find is used on your Server against your actual MongoDB, and on your Client against your local Minimongo DB.
Therefore on your client, once you have correctly subscribed to your server publication (typically at app level or template level / in onCreated hook), you can directly call Jobs.find in your helpers (or anywhere else) to get your documents, without having to change the subscription (unless the latter needs new parameters).
There should be nothing wrong with your commented code:
return Job.find({'_id': { '$in': companyJobs }});
In general, avoid any expensive computation in helpers (like Meteor.subscribe), as helpers may be executed many times without you noticing it. Your Meteor.subscribe('Companies') should also go to template level (i.e. in onCreated hook).
Therefore, instead of doing your if / else conditions in your helper, simply do it once at your template level. To account for your need to use a value from another document in another collection, why not just passing directly the company's slug as an argument to your Jobs subscription, and performing the computation Server-side? Or even just subscribing to everything, as your current initial subscription seems to do.
Then your helper will just use Jobs.find, which queries against your Client's local minimongo DB, leaving your Server unbothered.
So I do want to say that I've been searching for the answer for this and I've also tried to console.log my req.body post form and I keep getting undefined. So I feel that I'm losing the data from the form I send, I'm not sure what I"m doing wrong. So time to show some code.
As a note: I am using Handlebars for my Express Setup.
app.js
var express = require('express'),
exphbr = require('express3-handlebars'), // "express3-handlebars"
nodemailer = require('nodemailer'),
helpers = require('./lib/helpers'),
app = express(), handlebars;
// Create `ExpressHandlebars` instance with a default layout.
handlebars = exphbr.create({
defaultLayout: 'main',
helpers : helpers,
extname : '.html',
// Uses multiple partials dirs, templates in "shared/templates/" are shared
// with the client-side of the app (see below).
partialsDir: [
'views/shared/',
'views/partials/'
]
});
// Register `hbs` as our view engine using its bound `engine()` function.
app.engine('html', handlebars.engine);
app.set('view engine', 'html');
require("./routes")(app, express, nodemailer);
app.listen(3000);
routes.js
module.exports = function (app, express, nodemailer) {
// set up the routes themselves
app.get('/', function (req, res) {
res.render('home', {
title: 'Larry King Orchestra'
});
});
// I cut out a majority of my routes to make this easier to read.
// SEND EMAIL FROM FORM
app.post('/', function (req, res) {
console.log("WTF");
console.log(req.body.name);
console.log(req.body.email);
var mailOpts, smtpTrans;
//Setup nodemailer transport, I chose gmail. Create an application-specific password to avoid problems.
smtpTrans = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: "email#gmail.com",
pass: "password"
}
});
//Mail options
mailOpts = {
from: req.body.email, //grab form data from the request body object
to: 'anotheremail#gmail.com',
subject: 'LKO Contact Form',
html: 'From: ' + req.body.name + ' <' + req.body.email + '> <br>Phone: ' + req.body.tel + '<br>Date of Event: ' + req.body.date + '<br>Location: ' + req.body.location + '<br>Details & Comments:<br>' + req.body.message + '<br><br><p>Email form provided by WavaMedia.'
};
smtpTrans.sendMail(mailOpts, function (error, response) {
//Email not sent
if (error) {
res.render('home', {
title: 'Larry King Orchestra',
msg: 'Error occured, message not sent.',
err: true,
page: 'home'
});
}
//Yay!! Email sent
else {
res.render('home', {
title: 'Larry King Orchestra',
msg: 'Message sent! Thank you.',
err: false,
page: 'home'
});
}
});
});
// STATIC ROUTE FOR ASSESTS
app.use(express.static('assests/'));
};
I renamed the handlebars extension to be .html and I have the main layout using partials. SO app.get('/') will show this next file as a partial, and render it on the page.
contact.html
<form class="contact" action="/" method="post">
<label for="name">Name</label>
<input type="name" name="name" id="name">
<label for="email">Your Email (required)</label>
<input type="email" name="email" id="email">
<label for="tel">Phone Number</label>
<input type="tel" name="tel" id="tel">
<label for="date">Date of Your Event</label>
<input type="date" name="date" id="date">
<label for="location">Venue/Location</label>
<input type="location" name="location" id="location">
<label for-"message">Details & Comments</label>
<textarea name="message" id="message" rows="3"></textarea>
<input type="submit" name="submit" id="submit" value="Send" class="btn btn-default">
</form>
My Error:
TypeError: Cannot read property 'name' of undefined at c:\xampp\htdocs\lko\routes.js:129:26 at callbacks (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:164:37) at param (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:138:11) at pass (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:145:5) at Router._dispatch (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:173:5) at Object.router (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:33:10) at next (c:\xampp\htdocs\lko\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.expressInit [as handle] (c:\xampp\htdocs\lko\node_modules\express\lib\middleware.js:30:5) at next (c:\xampp\htdocs\lko\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.query [as handle] (c:\xampp\htdocs\lko\node_modules\express\node_modules\connect\lib\middleware\query.js:45:5)
So I'm not sure where I'm going wrong with the code. I believe the form is sending data to my node app, but where it's going, I'm not sure. I've setup the post method and so far no luck :( I have been trying for a couple days now. I have nodemailer installed as well. I've restarted the server, updated node and npm.
JavaScript Node Guru Masters, only you can show me the light! And thanks for reading though all of this, totally awesome!
app.use(express.bodyParser());
add that to your app.js
that's what grabs information from the post data form.
You have to require body parser package for this.
At first you have to install it with npm.
$ npm install --save body-parser
Then require that in your js file.
var bodyParser = require('body-parser');
Then add the parser. As you are using html post method it uses urlencoded as encoding type. For that add this line.
var urlencodedParser = bodyParser.urlencoded({ extended: false });
(If you use json you must use bodyParser.json() instead of this)
Now add the parser with the encoding type to app.post method as follows.
app.post('/',urlencodedParser, function (req, res) {
//your code here
});
You don't have to be explicitly mention any bodyParser or bodyParer.json
Instead You can make it simple to use this because this is a built-in middleware function in Express.
app.use(express.json());
app.use(bodyparser.urlencoded({extended : true }));
starting with angular, i am trying to GET data from the server and then POST back modifications with $resources.
It's working fine except the "save" function. No Data is POSTed back to the server.
here is the html
<div ng-controller="myCtrl">
<div ng-repeat="obj in objs">
<h2>{{obj.data_1}}</h2>
<h3>{{obj.data_2}}</h3>
<input type='text' ng-model="obj.data_1"><br/>
<textarea ng-model="obj.data_2" required></textarea><br/>
<button ng-click="save()">Save</button>
</div>
</div>
service.js
'use strict';
angular.module('App.services', ['ngResource']).
factory('Obj', function($resource){
return $resource('url/to/json');
});
controller.js:
'use strict';
angular.module('App.controllers', []).
controller('myCtrl', ['$scope', 'Obj', function($scope, Obj) {
$scope.objs = Obj.query();
$scope.save = function() {
$scope.objs.save();
}
}]);
Do you know why nothing is POSTed back when i save ?
Using the query method on the $resource object implies return as follows 'query': {method:'GET', isArray:true} it's mean that your $scope.objs is an array of objects and not an object and depending on number of elements you can use the folowing notation:
$scope.objs[i].save()
where i is the index of element in the array, forexample if you have return like:
[ {id:1, name:'Some name', age:35} ];
then your code : $scope.objs[0].save()
Edit:
I have created a plunk, maybe it will help you... http://plnkr.co/edit/62iPCAUNjV0oJROhul1G
Shouldn't there be another $resource declared for POST the way it is declared for GET? Each $resource specify particular REST service.
//services.js
'use strict';
angular.module('App.services', ['ngResource'])
.factory('GetObj', function($resource){
return $resource('url/to/json');
}
.factory('SaveObj', function($resource){
return $resource('url/to/post');
});
//controller.js
'use strict';
angular.module('App.controllers', []).
controller('myCtrl', ['$scope', 'GetObj', 'SaveObj', function($scope, GetObj, SaveObj) {
$scope.objs = Obj.query();
$scope.save = SaveObj.save(objs, function(resp) {
//Callback
console.log("Response from POST: %j", resp);
}
}]);