Import different components react from different files - javascript

How can I use component from another JS file in ReactJS.It says "Header is not defined".BTW I am using ReactJS without NodeJS.Here's the code:
<script type="text/babel" src="../Assets/js/react/Dashboard_components.js"></script>
//Here in Dashboard_components.js
var Dashboard_comp=React.createClass(
{
componentDidMount:function()
{
$('.ui.modal').modal();
},
render:function()
{
return(
<div>
//Header exists in Base component js
<Header/>
<div className="ui two columns grid">
<div className="three column wide">
<SideNav/>
</div>
<div className="thirteen column wide">
<Stats/>
<Class_boxes/>
</div>
</div>
</div>
)
}
})

At the top of your Dashboard_components.js file, and above the
var Dashboard_comp=React.createClass( line, add the line
var Header = require('./yourpath/to/header.js')
If you're using ES6 you can simply
import Header from './path/header'

Hmm..Seems like no-one got the answer so I am answering my own question.
Suppose there is a Header component in a Base_component.js file.So in order to use it in Other html's.Use this:
window.Header=Header
It would make component publicaly available for other files as well not the same js.

Related

How to use innerHTML for Accordion (PrimeReact)?

In my React project, I am using the PrimeReact library to display some Accordions. But I need to create them dynamically and this is the current result:
As you see, the html tags are also shown in the answers of the faqs. I tried using innerHTML and dangerouslySet... but to no success.
Here is my relevant code:
createAccordions = () => {
const allFAQs = this.state.allFAQs;
let accordions = [];
for (const faq of allFAQs) {
const accordion = <AccordionTab header={faq.question} dangerouslySetInnerHTML={{__html: `<p>yo man</p>`}}></AccordionTab>;
accordions.push(accordion);
}
return accordions
}
render() {
return (
<div className="component">
<h1 style={{textAlign: 'center'}}>{this.state.pageTitle}</h1>
<div className="p-grid">
<div className="p-col-3">
</div>
<div className="p-col-6">
<Accordion>
{this.createAccordions()}
</Accordion>
</div>
<div className="p-col-3">
</div>
</div>
</div>
)
}
How can I properly set the innerhtml for the accordions?
I took a look at the source and found that the library tries to render the children you pass to it. I see you tried dangerouslySetInnerHTML, but set it on the AccordionTab itself instead of the child passed into it.
I set up a quick demo on CodePen. I passed in a div container to set the innerHTML on, and it seems to work!
<AccordionTab header="Demo">
<div dangerouslySetInnerHTML={{ __html: "<ul><li>I am HTML</li></ul>" }}></div>
</AccordionTab>

Data Driven CSS Grid Vue Component

I want to create a Grid component that accepts the number of columns from the user, accepts data and renders all it's children into consecutive cells.
Something like this.
<Grid :cells="12" :columns="6">
<div>Child1 Cell1</div>
<div>Child2 Cell2</div>
<div>Child3 Cell3</div>
<div>Child4 Cell4</div>
<div>Child5 Cell5</div>
<div>Child6 Cell6</div>
</Grid>
In the Grid.vue component in the template, this is what I expect to do.
<div class="nugget-grid-item" v-for="cell of cells" :key="cell">
{cell}
</div>
This will render something like this on the UI.
The dashed border on each cell is due to the nugget-grid-item CSS class, but CSS is not relevant here, so let's ignore that.
What I am not able to figure out is how do I get this Grid component to display the following.
Isn't there something like this.children from React in Vue?
What you need are slots. See docs here. As you'll see slots allow a parent component to pass DOM elements into a child component. A basic look at them could go like this:
//ChildComponent.vue
<template>
<div>
<p>I'm the child component!</p>
<!-- Content from the parent gets rendered here. -->
<slot></slot>
</div>
</template>
And then you inject content into the slot tags like this:
//ParentComponent.vue
<template>
<div>
<child-component>
<p>I'm injected content from the parent!</p>
<p>I can still bind to data in the parent's scope, like this! {{myVariable}}</p>
</child-component>
</div>
</template>
Slots can get pretty complex and do a lot of things so are well worth looking into.
Further to your below comment, you can put a v-for in the grid. This outputs what you seem to be after. I've put an input in to accept the users number of columns as you said and it then renders that number of cells. You can of course use multiple slots and named slots and scoped slots but I'll leave it up to you how you expand on this.
//Grid.vue
<template>
<div class="cell">
<slot></slot>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.cell {
height: 40px;
width: 60px;
border: 1px solid gray;
}
</style>
and parent:
<template>
<div class="content">
<label>Enter number of columns</label>
<input v-model.number="col" type="number">
<Grid v-for="(n, i) in col" :key="i" >
<div>Child{{n}} Cell{{n}}</div>
</Grid>
</div>
</template>
<script>
import Grid from '#/components/admin/Grid'
export default {
layout: 'admin',
components: {
Grid
},
data: () => ({
col: 4
}),
}
</script>

ReactJS component not rendering textarea with state variable

I am facing an intriguing bug in React.
I have this component:
'use strict';
import SummaryStore from '../stores/SummaryStore';
import React from 'react';
export default class ChangeSummaryForm extends React.Component {
constructor() {
// store initialisation
SummaryStore.register();
var vRating = SummaryStore.getBookForSummaryPrint().summaryRating;
var vStarClassName = this.getRatingClasses(vRating);
this.state = {
sStarClassName: vStarClassName,
sCurrentBookToShow: SummaryStore.getBookForSummaryPrint()
};
this.thereIsASummaryToShow = this.thereIsASummaryToShow.bind(this);
}
getRatingClasses(pRating) {
var vI, vStarClassName = [];
for(vI = 0; vI < 4; vI++) {
if(pRating > 0) {
vStarClassName.push("glyphicon glyphicon-star");
pRating--;
} else {
vStarClassName.push("glyphicon glyphicon-star-empty");
}
}
return vStarClassName;
}
componentDidMount() {
SummaryStore.addChangeListener(this.thereIsASummaryToShow);
}
componentWillUnmount() {
SummaryStore.removeChangeListener(this.thereIsASummaryToShow);
}
thereIsASummaryToShow() {
this.setState({sCurrentBookToShow: SummaryStore.getBookForSummaryPrint(),
sStarClassName: this.getRatingClasses(SummaryStore.getBookForSummaryPrint().rating)
});
$("#summaryModal").modal('show');
}
render() {
return (<div className="modal fade" id="summaryModal">
<form>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal" ariaLabel="Close"><span ariaHidden="true">× </span> </button>
<div style={{color: 'black'}}>
{this.state.sStarClassName.map(function(pCurrentClassName) { return (<span className={pCurrentClassName}></span>
);
})}
<h4 className="modal-title">Summary of {this.state.sCurrentBookToShow.title}</h4>
</div>
</div>
<div className="modal-body">
<div className="form-group">
<textarea className="form-control" rows="22" ref="summaryContent" >{this.state.sCurrentBookToShow.summary}</textarea>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal" >Close</button>
<input type="submit" className="btn btn-primary" value="Save"/>
</div>
</div>
</div>
</form>
</div>
);
}
}
As you might notice, it's a controller-view listening at a store which is registered to my AppDispatcher.
The steps above are correctly performed. i.e, when the particular action is triggerd, my component is correctly rendered with the variables {this.state.sCurrentBookToShow.title} and this.state.sCurrentBookToShow.title up-to-date.
The problem comes from this part:
<textarea className="form-control" rows="22" ref="summaryContent" >
{this.state.sCurrentBookToShow.summary}
</textarea>
The string is not printed in the textarea.
I tried this to debug:
render() {
var summary = "this is a summary";
return (// .. shortened for brevity
<textarea className="form-control" rows="22" ref="summaryContent">
{summary}
</textarea> ..);
}
the summary string printed correctly inside the mutable textearea.
Note that my browser says:
Warning: Use the defaultValue or value props instead of setting
children on <textarea>.
But I will fix this later since I think it doesn't have an effect on the current problem.
EDIT:
I took your remarks (so far) in consideration, so I updated my code like so:
<h4 className="modal-title">Summary of {this.state.sCurrentBookToShow.summary}</h4>
</div>
</div>
<div className="modal-body">
<div className="form-group">
{this.state.sCurrentBookToShow.summary}
<textarea className="form-control" rows="22" ref="summaryContent" defaultValue={this.state.sCurrentBookToShow.summary}></textarea>
</div>
I replaced this.state.sCurrentBookToShow.title by .summary to make
sure the ladder is not empty.
I put the summary into a defaultValue prop
Here is the output:
Second edit:
I uploaded a sample app that highlights the issue. I hope this would help to find a proper solution
Check this link from react docs: React Textarea Value
Basically for textArea react does not supports text enclosed within and you rather need to specify that as value or defaultValue.
The right way thus is
<textarea name="description" value="This is a description." />
or
<textarea name="description" defaultValue="This is a description." />
The difference with value and defaultValue is that specifying defaultValue leaves the component uncontrolled:
With an uncontrolled component, you often want React to specify the initial value, but leave subsequent updates uncontrolled. To handle this case, you can specify a defaultValue attribute instead of value.
...while specifying value instructs React to control the component, meaning you need to update value property to make sure that change is reflected in the component:
Since the value attribute is set on our form element, the displayed value will always be this.state.value, making the React state the source of truth.
To get a clear idea of difference between value / default value check this: Fiddle for value Default Value Distinction Console will always show new value but component will not.
Actually that is exactly what is wrong. From the docs:
If you want to initialize the component with a non-empty value, you can supply a defaultValue prop.
I had the same problem. I solved it by using controlled component, e.g.
state.value = this.props.value
<textarea value={this.state.value} onchange={handler} />
It works fine to control the input part. However, I had another issue, I need to init/change the state.value to props.value whenever there is a re-render.
I used the lift-cycle methods and it works perfect fine.
componentWillReceiveProps: function(){
this.setState({
value: this.props.value
}) }
hope this helps.

Assign dynamic controller in ng-repeat

I am new to Angularjs. I've tried a example in here.
file index.html:
<div ng-repeat="data in ctl.dataList">
<div class="col-md-6">
<textarea type="text" ng-mouseover="ctl.mouseOverFunc()" ng-mouseleave="ctl.mouseLeaveFunc()">{{data.value}}</textarea>
<button ng-show="ctl.showCloseBtn">X</button>
</div>
</div>
file app.js:
app.controller('FocusController', function() {
this.showCloseBtn = false;
this.dataList = [{
value: "one"
}, {
value: "two"
}];
this.mouseOverFunc = function() {
this.showCloseBtn = true;
};
this.mouseLeaveFunc = function() {
this.showCloseBtn = false;
};
});
I want to show close button when mouse overed every textarea like facebook chat in this picture. But my issues is when mouse over one of textarea then all X button was showed.
How do i assign dynamic controller to every textarea or how to do like facebook chat ?
Thanks for your help
You can do with CSS as well as AngularJS. I suggest you to do with CSS which is Simple. And Do your ng-click on the button.
This Plunker Demo is using with CSS and added ng-click there. Please check the styles and classes added.
Styles
<style>
.field:hover .btn-close {
display:block;
}
.btn-close {
display:none;
}
</style>
HTML
<div ng-repeat="data in ctl.dataList">
<div class="col-md-7 field">
<textarea></textarea>
<button ng-click="doSomething()" class="btn-close">X</button>
</div>
</div>
This Plunker Demo is with AngilarJS as explained in the other answer by New Dev.
<div ng-repeat="data in ctl.dataList">
<div ng-mouseover="data.showX = true"
ng-mouseleave="data.showX = false">
<textarea></textarea>
<button ng-click="doSomething()" ng-show="data.showX">X</button>
</div>
Typically, it would be best to create a directive for this functionality and encapsulate all the logic of clicking the "x" button, but for simplicity you could also leverage the child scope created by ng-repeat, and do the following:
<div ng-repeat="data in ctl.dataList">
<div ng-mouseover="data.showX = true"
ng-mouseleave="data.showX = false">
<textarea type="text"></textarea>
<button ng-show="data.showX" ng-click="ctl.close(data)">X</button>
</div>
</div>
ng-repeat="item in items" creates a child scope for each item, so you can set values on the child scope.
Here's your modified plunker
EDIT:
As suggested in the comments, if you have nothing more complex than showing or hiding the button, definitely CSS approach is the simplest way to go. Use the above example then as an illustration for how scopes work.

jQuery find() function is returning different kind of results on different pages

I have a header bar with a search function on my site.
One of the functions I've implemented involves finding results and resizing the boxes that contain them.
One one page that has this header bar my function works perfectly:
$(".suggestionCategory").each(function() {
$(this).find(".suggestionCategoryName").outerHeight($(this).find(".suggestionCategoryValues").height());
});
But on another I get the following error message:
Uncaught TypeError: Cannot read property 'height' of undefined
Upon breaking and inspecting I can see the result of
$(this).find(".suggestionCategoryValues")
returns very different things. On the page that functions correctly:
$(this).find(".suggestionCategoryValues")
evaluates to:
[
<div class=​"suggestionCategoryValues">​…​</div>​
]
But on the page where it fails it evaluates to:
[
b.fn.b.init[1]
0: div.suggestionCategoryValues
context: div.suggestionCategoryValues
length: 1
__proto__: Object[0]
]
Why is this and what am I doing wrong?
EDIT:
First off - I don't want to know how to fix it - I've already got a workaround (do an inner foreach and total up the sizes of $(".suggestionCategoryValues").height().
But I'm curious as to why they are different.
The HTML is identical I believe but I will post the markup just in case I'm being an idiot.
This is the markup for the "broken" page:
<div id="searchSuggestionSelection" style="display: block; position: absolute; top: 3.9em; left: 324px; height: 343px;">
<div class="suggestionCategory">
<div class="suggestionCategoryName"><span>company</span></div>
<div class="suggestionCategoryValues">
<div data-actual-search="XXXX" class="suggestionValue first">XXXX</div>
<div data-actual-search="YYYY" class="suggestionValue">YYYY</div>
<div data-actual-search="ZZZZ" class="suggestionValue">ZZZZ</div>
</div>
</div>
<div class="suggestionCategory">
<div class="suggestionCategoryName"><span>contact</span></div>
<div class="suggestionCategoryValues">
<div data-actual-search="AAAA" class="suggestionValue first">AAAA</div>
<div data-actual-search="BBBB" class="suggestionValue">BBBB</div>
<div data-actual-search="CCCC" class="suggestionValue">CCCC</div>
<div data-actual-search="DDDD" class="suggestionValue">DDDD</div>
</div>
</div>
</div>
And this is the markup for the "working" page:
<div id="searchSuggestionSelection" style="display: block; position: absolute; top: 3.9em; left: 324px; height: 823px;">
<div class="suggestionCategory">
<div class="suggestionCategoryName" style="height: 316px;"><span>company</span></div>
<div class="suggestionCategoryValues">
<div data-actual-search="XXXX" class="suggestionValue first">XXXX</div>
<div data-actual-search="YYYY" class="suggestionValue">YYYY</div>
<div data-actual-search="ZZZZ" class="suggestionValue">ZZZZ</div>
</div>
</div>
<div class="suggestionCategory">
<div class="suggestionCategoryName" style="height: 512px;"><span>contact</span></div>
<div class="suggestionCategoryValues">
<div data-actual-search="AAAA" class="suggestionValue first">AAAA</div>
<div data-actual-search="BBBB" class="suggestionValue">BBBB</div>
<div data-actual-search="CCCC" class="suggestionValue">CCCC</div>
<div data-actual-search="DDDD" class="suggestionValue">DDDD</div>
</div>
</div>
</div>
As you can see the "working" page successfully gets heights applied.
I think it is because "this" is something else than you have expected, try storing it in a variable (called category) like this:
$(".suggestionCategory").each(function() {
var category = $(this);
var height = category.find(".suggestionCategoryValues").height();
category.find(".suggestionCategoryName").outerHeight(height);
});
When doing some testing I'm not sure why you would do
.find(".suggestionCategoryName").outerHeight($(this).find(".suggestionCategoryValues").height());
When I did my testing the parameter in the outerHeight is the same as if you set it to outerHeight(true);
$(".suggestionCategory").each(function() {
var category = $(this);
category.find(".suggestionCategoryName").outerHeight(true);
});
//other method
var suggestCat = $('.suggestionCategory'),i;
for(i=0;i<suggestCat.length;i++){
var indexCat = suggestCat[i];
$(indexCat).find('.suggestionCategoryName').outerHeight(true);
}
Also if you are trying to set the height of an element wouldn't it be easier to use the height function?
var suggestCat = $('.suggestionCategory'),i;
for(i=0;i<suggestCat.length;i++){
var indexCat = suggestCat[i];
$(indexCat).height(function(ele,index){
return this.find('.suggestionCategoryName').height();
});
}
As I am very unsure what the issue is perhaps or read your post wrong I could be providing it the wrong answers. You can also add an if statement to check if the element exist first.
try this
$(".suggestionCategory").each(function() {
var suggestionCategory = $(this);
suggestionCategory.find(".suggestionCategoryName").outerHeight(suggestionCategory.find(".suggestionCategoryValues").height());
});
Wow - that was a lot of effort for something so trivial.
On the "broken" page I was also including something called moorainbow. A colour picker that works with mooTools. The version I was including was about 7 years old, and for some reason it was interfering with jQuery in a hideously hard to detect way.
Possibly putting jQuery into no-conflict mode might have solved it, which is probably best practice anyway, but would have involved a fair amount of re-factoring of $'s into jQuery's. So instead I just removed the mooRainbow from the page and voila - problem solved, both pages act identically again.

Categories

Resources