Trying to get id parameter with nodejs and acces it in angular - node.js

I am trying to access a detail page that i have for a list of items in my html(ionic). So when I click on 1 item I need to go on a detail page with information about that specific item. I am using mongo database for the items , the model of the items are : name and ingredients.
I am stuck here and don't know what to do , please help if you have a bit of time , thank you.
My code :
<ion-list *ngFor="let recipe of recipes ; let i = index">
<ion-item>
<ion-label>{{recipe.name}}</ion-label>
</ion-item>
</ion-list>
Request for the database trying to get the id to access the item (I get the
public findByName(id: string) {
return this.http.get<any>(
"http://localhost:9020/:id" + id
);
}
This is what I tried in typescript
this.route.paramMap.subscribe((paramMap) => {
if (!paramMap.has("id")) {
this.navCtrl.navigateBack("/home");
return;
}
this._recipeDetail = this.nutService
.findByName(paramMap.get("id"))
.subscribe((id) => {
this.id = id;
});
});
Also in route module :
{
path: "name/:id",
loadChildren: () =>
import("./r-d/r-d.module").then(
(m) => m.RDPageModule
),
},
But its not working , maybe I don't have the right approach? Can someone please guide me a bit ?
Thank you for your time

this._recipeDetail = this.nutService
.findByName(paramMap.get("id"))
.subscribe((id) => {
this.id = id;
});
You should be expecting your api to return you the recipeDetail.. you are not storing it properly.
this.nutService.findByName(paramMap.get("id"))
.toPromise().then((data) => {
this.recipeDetail = data;
});
And then, you can display your recipeDetail inside your template. I have also changed .subscribe() to .toPromise().then(). This is a better approach to avoid memory leaks in your app.

Related

Update prop for dynamically inserted element

New to react... Really banging my head against it with this one... I'm trying to figure out how to get a dynamically inserted component to update when the props are changed. I've assigned it to a parent state object but it doesn't seem to re-render. I've read that this is what's supposed to happen.
I was using ReactDOM.unmountComponentAtNode to re-render the specific elements I needed to, but it kept yelling at me with red text.
I need to hide "chat.message" unless the user has the authority to see it (server just sends empty string), but I still need to render the fact that it exists, and reveal it should the user get authentication. I'm using a css transition to reveal it, but I really need a good way to update the chat.message prop easily.
renderChats(uuid){
let userState = this.state.userStates.find(user => {
return user.uuid === uuid;
});
const children = userState.chats.map((chat) => {
let ChatReactElement = this.getChatMarkup(chat.cuid, chat.message, chat.status);
return ChatReactElement;
});
ReactDOM.render(children, document.getElementById(`chats-${this.state.guid}-${uuid}`));
}
getChatMarkup() just returns JSX and inserts Props... I feel like state should be getting passed along here. Even when I use a for-loop and insert the state explicitly, it doesn't seem to re-render on changes.
getChatMarkup(cuid, message, status){
return(
<BasicChatComponent
key={cuid}
cuid={cuid}
message={message}
status={status}
/>
);
}
I attempted to insert some code line this:
renderChats(uuid){
let userState = this.state.userStates.find(user => {
return user.uuid === uuid;
});
const children = userState.chats.map((chat) => {
let ChatReactElement = this.getChatMarkup(chat.cuid, chat.message, chat.status);
if(chat.status.hidden)
this.setState({ hiddenChatRE: [ ...this.state.hiddenChatRE, ChatReactElement ] }); // <== save elements
return ChatReactElement;
});
ReactDOM.render(children, document.getElementById(`chats-${this.state.guid}-${uuid}`));
}
and later in my code:
this.state.hiddenChatRE.every(ReactElement => {
if(ReactElement.key == basicChats[chatIndex].cuid){
ReactElement.props = {
... //completely invalid code
}
}
});
The only response I see here is my ReactDOM.unmountComponentAtNode(); approach...
Can anyone point me in the right direction here?
Although perhaps I should be kicking myself, I read up on how React deals with keys on their components. So there's actually a fairly trivial answer here if anyone comes looking... Just call your render function again after you update the state.
In my case, something like:
this.setState(state =>({
...state,
userStates : state.userStates.map((userstate) => {
if(userstate.uuid == basicChats[chatIndex].uuid) return {
...userstate,
chats: userstate.chats.map((chat) => {
if(chat.cuid == basicChats[chatIndex].cuid){
//
return {
cuid: basicChats[chatIndex].cuid,
message: basicChats[chatIndex].message,
status: basicChats[chatIndex].status
}
}
else return chat;
})
}
else return userstate;
})
}));
and then, elsewhere in my example:
this.state.userStates.map((userstate) => {
this.renderChats(userstate.uuid);
});
Other than the fact that I'd recommend using indexed arrays for this example to cut complexity, this is the solution, and works. This is because even though it feels like you'd end up with duplicates (that was my intuition), the uid on the BasicChatComponent itself makes all the difference, letting react know to only re-render those specific elements.

Syncing React-Slick with Query Params

I'm using React-Slick to render <Report /> components in a carousel. I would like to sync each <Report />'s reportId with query params.
For example, a user would be able to see a specific report by going to myapp.com/reports?id=1 and it would take them to that specific "slide".
The problem I'm having is that the report data is being loaded before the slides are initialized. I can't find any good examples of react-slick's onInit or onReInit.
Instead of using onInit or onReInit, I just utilized the initialSlide setting and used componentDidUpdate().
componentDidUpdate = (prevProps, prevState) => {
const queryParams = qs.parse(this.props.location.search)
if (prevProps.reports !== this.props.reports) {
const sortedReports = this.sortReportsByDate(this.props.reports)
this.setSlideIndex(sortedReports.findIndex(i => i.id === parseInt(queryParams.reportId, 10)))
this.setQueryParams({
reportId: this.sortReportsByDate(this.props.reports)[this.state.slideIndex].id
})
}
if (prevState.slideIndex !== this.state.slideIndex) {
this.setQueryParams({
reportId: this.sortReportsByDate(this.props.reports)[this.state.slideIndex].id
})
}
}
And the settings:
const settings = {
...
initialSlide: reportsSortedByDate.findIndex(i => i.id === parseInt(queryParams.reportId, 10))
...
}
I hope someone finds this useful!

Getting image URL from Contentful entry id

I need to get an image URL from Contentful entry id.
I am getting such an JSON from Contentful query
{
"sys":{
"space":{
"sys":{
"type":"Link",
"linkType":"Space",
"id":"8v1e7eaw70p2"
}
},
"id":"1JfEwVlD9WmYikE8kS8iCA",
"type":"Entry",
"createdAt":"2018-02-28T18:50:08.758Z",
"updatedAt":"2018-02-28T18:50:08.758Z",
"revision":1,
"contentType":{
"sys":{
"type":"Link",
"linkType":"ContentType",
"id":"image"
}
},
"locale":"en-US"
},
"fields":{
"name":"heat",
"image":{
"sys":{
"type":"Link",
"linkType":"Asset",
"id":"6Inruq2U0M2kOYsSAu8Ywk"
}
}
}
}
I am using JS driver they provide:
client.getEntry()
so how to go thru that link: 6Inruq2U0M2kOYsSAu8Ywk ?
Unfortunately, the js SDK will not be able to resolve links when using the single entry endpoint i.e client.getEntry() because there won't be enough data.
When thing I always recommend to work around this is to use the collection endpoint with a query the desired id as a query param. This way you will always get the desired entry with all it's linked data.
Your code should look something like this
client.getEntries({'sys.id': '6Inruq2U0M2kOYsSAu8Ywk'})
.then(response => console.log(response.items[0].fields.image.fields.file.url))
I hope that helps.
Best,
Khaled
Use client.getEntries({'sys.id': '1JfEwVlD9WmYikE8kS8iCA'})
To get the entry fields and the asset fields.
You can also patch the assets to the fields by running this after fetching the data:
/* Patch all the assets to the fields */
const patchAssets = (fields, assets) => {
Object.keys(fields).forEach(function (key) {
let obj = fields[key];
if (obj.sys && obj.sys.linkType === 'Asset') {
const assetId = obj.sys.id;
const matchAsset = assets.find(asset => {
return asset.id === assetId;
});
obj.file = matchAsset;
}
});
return fields;
};
Another way to get image url is to use getAsset('<asset_id>'). So first, using the getEntry() method, you need to get the entry data, then extract the id from the field: fields.image.sys.id, and pass it to the getAsset method.

Migrating to FlowRouter, need something similar to a template data context

So I've read a lot on the discussion of Iron Router vs FlowRouter.
I started my project using Iron Router, but since changed my mind and I'm currently migrating to FlowRouter.
Everything was going smoothly until I started migrating the comments section of my app. You see, this section is reused several times on the app, it serves as a comment section for news, posts, photos, videos, etc.
Example using IR's data context:
Router.route('/news/:slug', {
name: 'newsItem',
waitOn: function() { Meteor.subscribe('news.single', this.params.slug) },
data: function() {
return News.findOne({slug: this.params.slug});
}
});
<template name="newsItem">
<p>{{title}}</p>
<p>{{body}}</p>
{{> commentSection}}
</template>
The Comment collection schema has a "type" (to know to what type of "thing" this comment belongs to, news, photos, etc). That type was set on the "form .submit" event of commentSection template. Example:
'submit form': function(e, template) {
e.preventDefault();
var $body = $(e.target).find('[name=body]');
console.log(template.data.type);
var comment = {
type: template.data.type,
parentId: template.data._id,
parentSlug: template.data.slug,
body: $body.val()
};
Meteor.call('insertComment', comment, function(error, commentId) {
if (error){
alert(error.reason);
} else {
$body.val('');
}
});
}
This worked because the template data context contained the News item which in turn has a a type property as well.
How could I achieve something similar to this only using Flow Router without setting data on the template as it is recommended by the official guide?
You'll want to use a template subscription and a {{#with}} helper probably.
Template.newsItem.onCreated( function() {
Template.instance().subscribe('news.single', FlowRouter.current().params.slug);
});
Template.newsItem.helpers({
item() {
let item = News.findOne();
if( item ) {
return item;
}
}
});
<template name="newsItem">
{{#with item}}
<!-- Your existing stuff -->
{{/with}}
</template>

Search information by user on firebase

This is probably very simple ,so sorry...
I'm trying to create an application where i can create users and store informations by Firebase. There is an example here :
http://image.noelshack.com/fichiers/2015/11/1426182307-log.png
But now I want to check if the name already exists if someone wants to create a new user.
How would I go about grabbing individual user information without knowing their id , like simplelogin:54?
I've found this topic Get users by name property using Firebase but it is not the same thing because in my case I don't know the children after "Users"
Cheers,
Like Frank said, you must know something about the user to be able to look her/him up.
However, here is a general answer. I am assuming that by "name" you mean the property "identifiant" that you've created.
Suggestions
Start by looking over the Firebase Query documentation.
Short Answer
To check if a user exists by the identifiant property, you'd orderByChild("identifiant") and query for a specific user with the .equalTo("<identifient_here>").
For example, to check if a user with identifient="aaa",
var usersRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/Users");
var identifient = "aaa";
usersRef.orderByChild("identifiant").equalTo(identifient).once("value", function(snapshot) {
console.log("Loaded user by identifient:",identifient,snapshot.val());
});
If instead you want to query by the key (such as simplelogin:53), you could query by using orderByKey() instead of orderByChild()... or just simply setting the ref to the user's key like so:
var userKey = 'simplelogin:53';
var userRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/Users" + userKey);
userRef.once("value", function(snapshot) {
console.log("Loaded user",snapshot.val());
});
Long(er) Answer
You can handle this with a user factory (see Angular Providers documentation).
You return a promise in the factory using the $q service.
Here is the Angular API documentation for $q.
Example with UserFactory
Check out this working PLNKR example.
It's tied to one of my public Firebase instances.
I created the same simplelogin:53 user in /Users like you have.
If you search for the identifient = aaa, you'll get the right user.
The controller implementation here is for example purposes, and doesn't really do anything worth while. It's just for reference.
The Data
{
"Users" : {
"simplelogin:53" : {
"identifiant" : "aaa"
}
}
}
UserFactory
.factory('UserFactory', function($q, $firebaseObject, fbUrl){
return function(userId){
var deferred = $q.defer();
if (userId.isNotEmpty()) {
var userRef = new Firebase(fbUrl + '/Users/').orderByChild("identifiant").equalTo(userId);
userRef.once("value",
function(dataSnapshot){
if (dataSnapshot.val()) {
console.log("Loaded user",dataSnapshot.val());
deferred.resolve(dataSnapshot.val());
} else {
console.info("Couldn't find user by id",userId);
deferred.reject("No user found by identifient = '"+userId+"'");
}
},
function(error){
console.error("Error loading user",error);
deferred.reject(error);
}
);
} else {
deferred.reject("No id entered!");
}
return deferred.promise;
}
})
Controller
.controller('HomeController',function($scope, UserFactory) {
$scope.identifient = '';
var showError = function(errorMessage) {
if (errorMessage) {
showUser(false);
$scope.error = errorMessage;
} else {
delete $scope.error;
}
}
var showUser = function (userObject) {
if (userObject) {
showError(false);
$scope.user = userObject;
} else {
delete $scope.user;
}
}
$scope.loadUser = function() {
var userPromise = new UserFactory($scope.identifient);
userPromise.then(function(data){
showUser(data);
}).catch(function(error){
showError(error);
});
}
})
Template
<div ng-controller="HomeController">
<h2>Home Template</h2>
<input ng-model="identifient" placeholder="identifient"/>
<button ng-click="loadUser()">Find User</button>
<hr/>
<div ng-if="user">User: {{user}}</div>
<div ng-if="error">Error: {{error}}</div>
</div>
Hope that helps.

Resources