Looping in React, how to get a prop.username from child component - javascript

I have this code, which renders a Friends List block. Next to the name, there is an action dropdown menu, where there are several buttons, i need to seperate each button and on which user it belongs. So far it works, but outputs all the usernames, one by one. Check on the dropdown menu the onClick Alert. There when i press the href, nothing happens, though, when new content loads, it pops up alert foreach user listed.
var UserDropdownActions = React.createClass({
handlesendMessage: function(username){
console.log(username);
},
render: function() {
return(
<div className="tbl-cell tbl-cell-action">
<div className="btn-group">
<button type="button" className="btn btn-rounded btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Connect
</button>
<ul className="dropdown-menu">
<li><a className="dropdown-item" href="javascript:;" onClick={alert(this.props.username)}><span className="font-icon font-icon-home"></span>Quant and Verbal</a></li>
<li><a className="dropdown-item" href="javascript:;"><span className="font-icon font-icon-cart"></span>Real Gmat Test</a></li>
<li><a className="dropdown-item" href="javascript:;"><span className="font-icon font-icon-speed"></span>Prep Official App</a></li>
<li><a className="dropdown-item" href="javascript:;"><span className="font-icon font-icon-users"></span>CATprer Test</a></li>
<li><a className="dropdown-item" href="javascript:;"><span className="font-icon font-icon-comments"></span>Third Party Test</a></li>
</ul>
</div>
</div>
);
}
})
var UserDisplayNameFields = React.createClass({
render: function(){
return(
<div className="tbl-cell">
<p className="user-card-row-name status-online">{this.props.username}</p>
<p className="user-card-row-location">{this.props.hobby}</p>
</div>
);
}
});
var UserPreviewCircularImage = React.createClass({
render: function(){
return(
<div className="tbl-cell tbl-cell-photo thumbnail-wrapper d32 circular inline m-t-5">
<a href={"/user/" + this.props.username}>
<img src={this.props.avatar} alt={this.props.username} />
</a>
</div>
);
}
});
var UserSmallView = React.createClass({
render: function() {
return (
<div className="friends-list-item">
<div className={"user-card-row user_" + this.props.username}>
<div className="tbl-row">
<UserPreviewCircularImage avatar={this.props.avatar} username={this.props.username} />
<UserDisplayNameFields username={this.props.username} hobby={this.props.hobby} />
<UserDropdownActions username={this.props.username} />
</div>
</div>
</div>
);
}
});
var FriendList = React.createClass({
render: function() {
return (
<div className="friends-list">
{
this.props.users.map( (user, i) => {
return(
<UserSmallView
key={i}
username={user.username}
hobby={user.hobby}
avatar={user.avatar} />
)
})
}
</div>
);
}
});

My mistake was that i was trying to send to the function the username, though, it was already there.
i added a function where it alerts the prop.username
handlesendMessage: function(){
alert(this.props.username);
},
instead of,
handlesendMessage: function(username){
alert(username);
}

Related

Vue.js - how to hide an image with the hover event on it and show another?

I have two images whose behavior I want to see next.
By default the image will be shown with the name 'home' and with the event 'mouseover' I want to hide and show the image with the name 'blackhome'.
I have the two images shown on screen and there's nothing happens with the mouse events
I don't know if this is possible.
Here's a codepen link with the issue
https://codepen.io/CharlieJS/pen/gOrayzW
this is my template
<li class="nav-item" #mouseover="homeLink = !homelink" #mouseleave="!homeLink" >
<a class='nav-link home' href="https://www.google.com/">
<img v-if="homeLink" class="logo" src="../../assets/home.png">
<img v-if="!homelink" src="../../assets/blackhome.png">
</a>
</li>
and my script
export default {
data: function () {
return {
homeLink: false
}
},
computed: {
auth () {
return this.$store.getters.isAuthenticated
}
},
methods: {
onLogout() {
this.$store.dispatch('logout')
},
}
}
</script>
Thank you in advance for your time and help
Try v-if and v-else as follows :
<li class="nav-item" #mouseover="homeLink = !homelink" #mouseleave="homeLink=false" >
<a class='nav-link home' href="https://www.google.com/">
<img v-if="homeLink" class="logo" src="../../assets/home.png"/>
<img v-else src="../../assets/blackhome.png"/>
</a>
</li>
let app = new Vue({
el: "#app",
data: function() {
return {
homeLink: false
}
},
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<li class="nav-item" #mouseover="homeLink = !homelink" #mouseleave="homeLink=false">
<a class='nav-link home' href="https://www.google.com/">
<img v-if="homeLink" class="logo" src="https://picsum.photos/300/200?image=244" />
<img v-else src="https://picsum.photos/300/200?image=1024" />
</a>
</li>
</div>

Component's values not being updated

I created a Vue app, where I have a single HTTP request. Once the data returns, I update the profile value. But all components using this value do not get reloaded. Below is the code to better explain what I am trying to accomplish.
I have the main Vue file App.vue:
<template>
<div id="app">
<Navigation />
<Header :profile="profile" />
<About :profile="profile" />
<Services :profile="profile" />
</div>
</template>
<script>
import Navigation from './components/Navigation.vue'
import Header from './components/Header.vue'
import About from './components/About.vue'
import Services from './components/Services.vue'
export default {
name: 'app',
components: {
Navigation,
Header,
About,
Services,
},
data() {
return {
profile: { }
}
},
created() {
this.getUserProfile()
},
methods: {
getUserProfile: async function() {
try {
const response = await fetch('http://localhost:7070/v1/home');
const data = await response.json();
this.profile = data;
} catch (error) {
console.error(error);
}
}
}
}
</script>
<style>
</style>
As you can see, I set the variable profile to empty object at the start. And once the app enters the mounted state, I can the GET request to retrieve the profile data. When I debug, I can clearly see data is not an empty object. The response contains all data.
As you can see from the app file, I import 4 files to add 4 components to the app. All components are done in the same principle.
Here is the navigation.vue content:
<template>
<nav class="navbar navbar-expand-lg navbar-light fixed-top py-3" id="mainNav">
<div class="container">
<a class="navbar-brand js-scroll-trigger" href="#page-top">Home</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto my-2 my-lg-0">
<li class="nav-item">
<a class="nav-link js-scroll-trigger" href="#about">About</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll-trigger" href="#services">Services</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll-trigger" href="#career">Career</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll-trigger" href="#contact">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
</template>
<script>
</script>
<style scoped>
</style>
Component header.vue:
<template>
<header class="masthead">
<div class="container h-100">
<div class="row h-100 align-items-center justify-content-center text-center">
<div class="col-lg-10 align-self-end">
<h1 class="text-uppercase text-white font-weight-bold">{{ fullName }}</h1>
<h2 class="text-uppercase text-white font-weight-bold">{{ profession }}</h2>
<hr class="divider my-4">
</div>
<div class="col-lg-8 align-self-baseline">
<p class="text-white-75 font-weight-light mb-5">{{ oneLiner }}</p>
<a class="btn btn-primary btn-xl js-scroll-trigger" href="#about">Find Out More</a>
</div>
</div>
</div>
</header>
</template>
<script>
export default {
props: {
profile: Object
},
computed: {
fullName: function () {
if (typeof(profile) == 'undefined') {
return 'Jernej Klancic';
}
return profile.firstname + ' ' + profile.lastname;
},
profession: function() {
if (typeof(profile) == 'undefined') {
return 'Developer';
}
return profile.profession;
},
oneLiner: function() {
if (typeof(profile) == 'undefined') {
return '';
}
return profile.oneLiner;
}
}
}
</script>
<style scoped>
</style>
Component about.vue:
<template>
<section class="page-section bg-primary" id="about">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8 text-center">
<h2 class="text-white mt-0">About</h2>
<hr class="divider light my-4">
<p class="text-white-50 mb-4">{{ aboutMe }}</p>
<a class="btn btn-light btn-xl js-scroll-trigger" href="#services">Expertise</a>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
props: {
profile: Object
},
computed: {
aboutMe: function () {
if (typeof(profile) == 'undefined') {
return '';
}
return profile.aboutMe;
}
}
}
</script>
<style scoped>
</style>
Component service.vue:
<template>
<section class="page-section" id="services">
<div class="container">
<h2 class="text-center mt-0">At Your Service</h2>
<hr class="divider my-4">
<div class="row">
<div v-for="skill in skills" v-bind:key="uuid" class="col-lg-3 col-md-6 text-center">
<div class="mt-5">
<i v-bind:class="fontAwesomeDecorator(skill)"></i>
<h3 class="h4 mb-2">{{ skill.type }}</h3>
<p class="text-muted mb-0">{{ skillLevel(skill) }}</p>
</div>
</div>
<div class="col-lg-3 col-md-6 text-center">
<div class="mt-5">
<i class="fas fa-4x fa-laptop-code text-primary mb-4"></i>
<h3 class="h4 mb-2">Other</h3>
<p class="text-muted mb-0">Always eager to learn new language or framework</p>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
props: {
profile: Object
},
computed: {
skills: function () {
if (typeof(profile) == 'undefined') {
return [];
}
return profile.favoriteExpertise.proficient.slice(0, 3);
}
},
methods: {
fontAwesomeDecorator: function(skill) {
var style = ['fab', 'fa-4x', 'text-primary', 'mb-4'];
var uppercase = skill.type.toUpperCase();
if (uppercase === 'JAVA') {
style.push('fa-java');
}
if(uppercase === 'JAVASCRIPT') {
style.push('fa-js');
}
if(uppercase === 'ANDROID') {
style.push('fa-android');
}
return style;
},
skillLevel: function(skill) {
switch(skill.rating) {
case 10:
return `Living and breathing ${skill.type} code`;
case 9:
return `${skill.type} marksmen`;
case 8:
return `Bug slayer in the ${skill.type} realm`;
case 7:
return `${skill.type} fanboy`;
case 6:
return `Level ${skill.rating} ${skill.type} wizard`;
case 5:
return `${skill.type} nerd`;
default:
return `${skill.type} motivator stage ${skill.type}`;
}
}
}
}
</script>
<style scoped>
</style>
Can anyone tell what could be wrong? Should I change my approach? Is there a better way to do this in Vue? As said, I retrieve the profile JSON object from the backend. I reassign the profile variable by using this.profile = data; in App.vue. Should this not trigger a reload of data?
You need to access the profile prop using this.profile within the JavaScript portion of you component.
For example, this won't work:
skills: function () {
if (typeof(profile) == 'undefined') {
return [];
}
return profile.favoriteExpertise.proficient.slice(0, 3);
}
Instead of just profile you need to write this.profile.
The ability to drop the this. in the template does not carry over to elsewhere. That's specifically a feature of the templating language. In the <script> section you need to include the this. just like you would in any other JavaScript code. Props, data, computed properties and methods are all accessed as properties of the Vue instance in this way.

Passing parameters with dropdown on AngularJS

I'm trying list data according with data choose on a drop down menu.
My service list data with a hardcode (id 6).
var url = 'http://localhost:3854/listarServicosByEstab/' + '6'; // Hardcode!
How do I pass the select item ID to the service?
Dropdown HTML (ng-click doesnt work):
<!-- Combobox -->
<div class="row">
<div class="dropdown" ng-controller="EstabelecimentosPageCtrl">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdown_estabelecimentos" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Estabelecimentos
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdown_estabelecimentos" >
<li>
<a ng-repeat="estab in listaDeEstabelecimentos" href="#" ng-click="$parent.current = item">
{{estab.nomeEstab}}
</a>
</li>
</ul>
Choose Test: {{item}}
</div>
</div>
Menu Controller:
.controller('ListServicoCtrl', function($scope, $state, ListServicoService) {
ListServicoService.listarServicos().then(function(dados){
$scope.listaDeServicos = dados;
}); });
Service:
.service('ListServicoService', function($http){
var url = 'http://localhost:3854/listarServicosByEstab/' + '6'; // Hardcode!
return{
listarServicos : function (){
return $http.get(url).then(function(response){
return response.data;
});
}
}});
<div class="row">
<div class="dropdown" ng-controller="EstabelecimentosPageCtrl">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdown_estabelecimentos" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Estabelecimentos
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdown_estabelecimentos" >
<li>
<a ng-repeat="estab in listaDeEstabelecimentos" ng-click="passdata(estab.Id)">
{{estab.nomeEstab}}
</a>
</li>
</ul>
Choose Test: {{item}}
</div>
</div>
Your Controller
.controller('ListServicoCtrl', function($scope, $state, ListServicoService) {
$scope.passdata = function(id){
ListServicoService.listarServicos(id).then(function(dados){
$scope.listaDeServicos = dados;
});
} });
Your Service
.service('ListServicoService', function($http){
return{
listarServicos : function (id){
return $http.get('http://localhost:3854/listarServicosByEstab/' + id).then(function(response){
return response.data;
});
}
}});
Remove href from anchor tag and make a function like I have shown in controller. By assuming that your json contains value like Id I have demonstrated it. Hope this code will work for you.

Why onClick in my React class is not working

Below is my React Component
var NavHead = React.createClass({
getInitialState: function() {
return { in: 0};
},
handleClicking: function(event){
var text=0;
console.log(this.state.in);
},
render: function(){
return(
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
<a className="navbar-brand" href={this.props.url} >
<img src={this.props.img_src} alt="tm-logo" onClick={this.handleClicking}/>
</a>
</div>
);
}
});
However, when I click the logo, there is nothing happened. Is there anything wrong in my code?
For more information, I have more than 20 components in my file. I have tried to copy-paste onClick handler to every component, and found that there is only 1 component that the code works. Below is that component.
var NavBarMenu = React.createClass({
getInitialState: function() {
return { itemClick: 0};
},
handleClick: function(event) {
console.log(this.state.itemClick)
this.setState({itemClick: event.currentTarget.dataset.id});
},
render: function(){
return(
<ul className="nav navbar-nav navbar-menu">
{this.props.data.map(function(object, i){
return <li onClick={this.handleClick} data-id={i} className={this.state.itemClick==i?"active":""}><a href={object.url}>{object.name}</a></li>;
},this)}
</ul>
);
}
});
I tried to run your code, and run into the same issue.
I fixed it by changing the order of required react js files. The react-dom.js library was included before react.js
Something similar to:
<script src="react.js"></script>
<script src="react-dom.js"></script>
The key thing is react-dom.js should come after react.js.
I think your javascript engine is optimizing out your code in the first case because it is only doing a console.log. In the second case, state is mutated so the code is kept around.

React onClick event only triggerable once after compiling from jsx to js

I have a component that builds a list of images with 2 buttons on each array entry.
One of the 2 buttons has an onClick event which updates its parentComponent so that the image is shown in a bigger view.
Everything works perfectly in the precompilex jsx version. But as soon as i try out the "live" compiled version the onClick event only works once.
To make it work on another element I need to reload the page.
I don't get any console errors. No idea where the error might be.
If you want to recreate it you can paste the code and create a div with the id "bilder".
I am using the latest react version :
<script src="some-react-CDN-0.13.3.js"></script>
<script src="some-react-CDN/JSXTransformer-0.13.3.js"></script>
Heres the source :
var Bilder = React.createClass({
getInitialState: function() {
return {
data:[
['1', '/app/public/imgs/image.jpg', 'bild1.jpg'],
['2', '/app/public/imgs/image.jpg', 'bild2.jpg'],
['3', '/app/public/imgs/image.jpg', 'bild3.jpg'],
['4', '/app/public/imgs/image.jpg', 'bild4.jpg'],
['5', '/app/public/imgs/image.jpg', 'bild5.jpg']
],
currentPic:[],
display:'showBild clearfix dn',
displayBg:'darkBg dn'
};
},
showBild: function(e, data){
this.setState({
currentPic: e,
display: 'showBild clearfix db',
displayBg: 'darkBg db'
});
},
hide: function(){
this.setState({
display: 'showBild clearfix dn',
displayBg: 'darkBg dn'
});
},
render: function() {
return (
<div>
<SingleBild data={this.state.data} chosenBild={this.showBild} />
<BildDetail hide={this.hide} data={this.state.currentPic} display={this.state.display} displayBg={this.state.displayBg} />
</div>
);
}
});
var SingleBild = React.createClass({
getInitialState: function() {
return {
bild:[]
};
},
showBild: function(data, e){
e.preventDefault();
this.props.chosenBild(data);
},
render: function() {
var scopeThis = this;
var displayBild = function(bild){
return <li><img src={bild[1]} alt="" /><span>{bild[2]}</span><a onClick={scopeThis.showBild.bind(null, bild)} href="#"><i className="fa fa-eye"></i></a><i className="fa fa-trash-o"></i></li>
};
return (
<ul className="dashboardUl bilder clearfix">
<h2>Gemeldete Bilder:</h2>
{this.props.data.map(displayBild)}
</ul>
);
}
});
var BildDetail = React.createClass({
hide: function(){
this.props.hide();
},
render: function() {
return (
<div>
<div className={this.props.display}>
<img src={this.props.data[1]} alt="" />
<span>{this.props.data[2]}</span>
<ul>
<li><i className="fa fa-trash-o"></i></li>
<li><i className="fa fa-ban"></i></li>
</ul>
</div>
<div onClick={this.hide} className={this.props.displayBg}></div>
</div>
);
}
});
React.render(<Bilder />, document.getElementById('bilder'));
I think you should remove the mapping of data onto list nodes out of the return statement in render and then bind component Class to to the map callback function.
...
render: function() {
var listNodes = this.props.data.map(function(bild) {
return (
<li>
<img src={bild[1]} alt="" />
<span>{bild[2]}</span>
<a onClick={this.showBild} href="#">
<i className="fa fa-eye"></i>
</a>
<a href="#">
<i className="fa fa-trash-o"></i>
</a>
</li>
)
}.bind(this));
return (
<ul className="dashboardUl bilder clearfix">
<h2>Gemeldete Bilder:</h2>
{listNodes}
</ul>
);
}
Now

Categories

Resources