Updated My Question based on comments. Not able to make small snippets as its a legacy code with lot of interacting components and I am very new to React to understand all the components.
I have the following GUI:
If you see carefully I have multiple fields with corresponding dropdowns. This combination is represented within a Div in my code under a class within render() function.
The problem is the Div code is repeatedly copy-paste to create a new
field and dropdowns. I don't want to repeat the whole div again and
again and want to replace it with some variable or function which
accepts Field name and DROP_DOWN_TYPE.
I have tried many solutions but it resulted in various errors due to
onchange event.
Repeated div is shown below:
<div className="infoBlock">
<div className="row align-items-center">
<div className="col-6">
<div className="row">
<div className="col-4">
<label className="b_label">Category :</label>
</div>
<div className="col-8">
<Dropdown type="Categories" isMultiple={true} onchange={this.handleDDClick} />
</div>
</div>
</div>
<div className="col-6">
</div>
</div>
</div>
I can't show DropDown code because its a huge file. But its a normal drop down which makes a service call to populate its fields.
Can you give more clarity by making a demo kind of thing on codesandbox.io ?
What I feel is you are repeatedly calling the setState function according to the error.
Either your state is being called repeatedly somewhere , or you need to bind that this.handleDDClick onto that onchange in Dropdown tag. Sometimes it gets triggered without actually any change happening in the dropdown.
Related
I have an Angular 9 app (upgraded from 7 recently, but still had same issue in 7) and in my app.component.html file I have this code below.
The page loads correctly and everything looks good.
But the method
getSideBarState() // returns a boolean
in both 'toggled' and 'show' ngClass get triggered and run at least 10+ times when I first start up the debugger. And then after the last one runs, it waits about ~10 secs and then ~10 get triggered again and run. And this keeps going and going endlessly being triggered and run.
Can anyone tell me why, and how to stop it from being triggered and run so many times? I only want it to run once when the app first loads.
<div class="page-wrapper" [ngClass]="{'toggled' : getSideBarState()}" (window:resize)="onResize()">
<app-sidebar></app-sidebar>
<main class="page-content">
<div class="">
<app-nav-bar></app-nav-bar>
<router-outlet (activate)="onActivate($event)"></router-outlet>
</div>
<div class="overlay" (click)="toggleSidebar()" [ngClass]="{'show' : !getSideBarState()}"></div>
</main>
</div>
This is working as per the design of Angular.
getSideBarState will get called every time change detection runs in Angular application, on almost every life cycle hook and many more times (Which I don't know at the moment), because you are using function (which returns something to the template) in the template instead of simple variable Binding.
How you avoid this?
In order to avoid call you function getSideBarState in ngOnInit or other suitable life cycle hook and assign the return value to one variable and then bind to that variable in the template, in that way it won't run multiple times.
For example -
ngOnInit() {
getSideBarState();
}
getSideBarState() {
... Some calculations (here `classState` is variable)
classState = true/false; // return value
}
<div class="page-wrapper" [ngClass]="{'toggled' : classState}" (window:resize)="onResize()">
<app-sidebar></app-sidebar>
<main class="page-content">
<div class="">
<app-nav-bar></app-nav-bar>
<router-outlet (activate)="onActivate($event)"></router-outlet>
</div>
<div class="overlay" (click)="toggleSidebar()" [ngClass]="{'show' :!classState}"></div>
</main>
</div>
Hope this answer will help you.
I have a React class in which I get a list of object and need to put them into a table. That part is working fine. Now I need to implement a filter for each title that if the user types something in that input box, then based on where it was (under header1, header2, etc), it will sort according to that and what was written in the box.
So lets say that header1 would be userID and I would type in 23 into the input box under header1, then it would return only those items from the list where userID starts with 23.
renderItems(myList) {
return (
<div className="report-table">
<div className="report-table-header">
<div className="report-table-cell">header1</div>
<div className="report-table-cell">header2</div>
<div className="report-table-cell">header3</div>
<div className="report-table-cell">header4</div>
<div className="report-table-cell">header5</div>
<div className="report-table-cell">header6</div>
<div className="report-table-cell">header7</div>
<div className="report-table-cell">header8</div>
</div>
<div className="report-table-header">
<div className="report-table-cell"><input></input></div>
<div className="report-table-cell"><input></input></div>
<div className="report-table-cell"><input></input></div>
<div className="report-table-cell"><input></input></div>
<div className="report-table-cell"><input></input></div>
<div className="report-table-cell"><input></input></div>
<div className="report-table-cell"><input></input></div>
<div className="report-table-cell"><input></input></div>
</div>
{mySortedList.map(item => (
<MyListItem key={item.id} {...item} />
))}
</div>
);
}
Any suggestions that would get me started?
It's pretty trivial problem. You could either use a library for tables (literally any, e.g. https://github.com/tannerlinsley/react-table). Or you might write the code on your own. As long as the number of headers is static, you could collect the filter values into some object:
const filters = {
name: '', // no filtering for this header
city: 'island', // this header has a user input
}
Later you could use loadsh _.filter(rows, filters)
So the basic React lifecycle is that you a this.state variable in your constructor() (with defaults). Use this to store both your search queries and your data.
You will need a tag with your <input>/<select> controls, that have an onChange() event that triggers this.setState(). This will trigger componentDidUpdate(prevProps, prevState, snapshot). Check if your search terms have changed, and then update this.state.data with whatever raw information you want to display in your list.
render() will then be able to loop/map over this.state.data to display your list.
Read up on the React Component Lifecycle
https://reactjs.org/docs/react-component.html
Here is an example of some recent code I wrote showing this pattern.
https://github.com/JamesMcGuigan/elasticsearch-tweets/blob/master/src/components/TweetHeatMap/TweetHeatMap.jsx
https://tweets.elasticsearch.jamesmcguigan.com/ (webpage result)
I'm following this Ember tutorial and I've suddenly run into an issue where my rental-listing.hbs template component stops rendering. It started when I began implementing the map service.
I don't understand where this could be happening. I've copied the code from parts of the GitHub repository that I thought were relevant but to no avail.
I have a rental.hbs template that looks like so:
<div class="jumbo">
<div class="right tomster"></div>
<h2>Welcome!</h2>
<p>We hope you find exactly what you're looking for in a place to stay.</p>
{{#link-to "about" class="button"}}
About Us
{{/link-to}}
</div>
{{outlet}}
Which in turn has a template component called rental-listing.hbs:
<article class="listing">
<a
onclick={{action "toggleImageSize"}}
class="image {{if this.isWide "wide"}}"
role="button"
>
<img src={{this.rental.image}} alt="">
<small>View Larger</small>
</a>
<div class="details">
<h3>{{link-to this.rental.title "rentals.show" this.rental class=this.rental.id}}</h3>
<div class="detail owner">
<span>Owner:</span> {{this.rental.owner}}
</div>
<div class="detail type">
<span>Type:</span> {{rental-property-type this.rental.category}} - {{this.rental.category}}
</div>
<div class="detail location">
<span>Location:</span> {{this.rental.city}}
</div>
<div class="detail bedrooms">
<span>Number of bedrooms:</span> {{this.rental.bedrooms}}
</div>
</div>
<LocationMap #location={{this.rental.city}}/>
</article>
The only thing I have added to the above is the line <LocationMap #location={{this.rental.city}}/> but it still doesn't work if I remove it.
The console shows me no errors and I can actually see I am getting the three dummy objects I want from Mirage:
So I'm definitely getting the objects and from what I see I'm doing everything necessary in the templates to render it but they aren't. Should I be looking somewhere else?
Are you able to provide a link to your example? By having each piece of the ember application you mention it would be best to answer definitely. I can give a general answer with strategies for debugging the template.
The conventions behind ember.js make understanding the "whys" frustrating at first and possibly opaque. Ember's handlebars implementation governs how values are populated and accessed within templates using very specific rules. Ember treats templates (handlebars files) differently depending on whether it is for a route or component. Component's have an isolated context and must receive values by explicit passing in or dependency injection. Then, you can use such values in a component's template by accessing those properties with {{this.somePassedInValue}}.
In the super-rentals app, it appears the rental index route invokes the components responsible for displaying the individual units. I found this in app/templates/rentals/index.hbs.
<li><RentalListing #rental={{rentalUnit}} /></li>
The route template iterates over the list of filteredResults. Each of these is the rentalUnit. A good first step would be to use the {{log}} helper to print out that the value of rentalUnit to ensure it is what you expect.
Alternatively, you could try cloning https://github.com/ember-learn/super-rentals and applying the changes you want to make step by step from the master branch. By doing so, you could easily undo a single change to see what caused something to not show up as expected.
<LocationMap #location={{this.rental.city}}/>
to be written as below
<LocationMap #location={{this.rentals.city}}/>
may be typo error.
also repeat this for there place in that template.
Because the model name in the console is rentals not rental
I am facing some issue. I have some nested controller within one parent controller and I need it to execute as per some condition using Angular.js. I am explaining my code below.
NABH.html:
<div ng-controller=NABHParentController>
<div ng-show="showNabh">
<div ng-include="'nabh1.html'"></div>
</div>
<div ng-show="showNabh1">
<div ng-include="'nabh2.html'"></div>
</div>
</div>
nabh1.html:
<div class="right_panel" style="display:block;" id="auditnabh" ng-controller="NABHController">
<td class="sticky-cell" ng-click="initiateNABH(nabh.NABHAuditID)">
</td>
</div>
nabh2.html:
<div class="right_panel" ng-controller="NABH2Controller">
<h2 class="page-title">NABH (INT012017001)</h2>
<div>
NABHParentController.js:
var app=angular.module('demo');
app.controller('NABHParentController',function($scope,$http,$state,$window,$location,$filter){
$scope.showNabh=true;
$scope.showNabh1=false;
})
NABHController.js:
var app=angular.module('demo');
app.controller('NABHController',function($scope,$http,$state,$window,$location,$filter,getBothIdToAuditDetailPage)
{
$scope.initiateNABH = function(aid) {
$scope.$parent.$parent.showNabh=false;
$scope.$parent.$parent.showNabh1=true;
}
})
Here Initially all controller are loading and nabh1.html is displaying first. When user will click on that td click event the second part html is showing. Here I need when user will click on that ng-click="initiateNABH(nabh.NABHAuditID)" the second view will open and the resepective controller will start execute. Initially only displaying view related controller will execute. Please help.
It sounds like using ng-if instead of ng-show will solve your problem:
<div ng-if="showNabh">
<div ng-include="'nabh1.html'"></div>
</div>
<div ng-if="showNabh1">
<div ng-include="'nabh2.html'"></div>
</div>
The difference is that while ng-show will "only" hide the element using css when the expression is falsy, ng-if will not create the element if it's falsy and as a result will not initiate the controller until ng-if is truthy.
Also, I would probably move the initiateNABH function to the parent controller - it will still be available in the child controller but makes the code less likely to break since you don't have to use $parent:
var app=angular.module('demo');
app.controller('NABHParentController',function($scope,$http,$state,$window,$location,$filter){
$scope.showNabh=true;
$scope.showNabh1=false;
$scope.initiateNABH = function(aid) {
$scope.showNabh=false;
$scope.showNabh1=true;
}
})
I have read and understood the use of a forms $pristine/$dirty property to detect changes to a form's data.
However, in trying to keep my UI friendly, I have split my various data fields over a number of tabs (I'm using angular-bootstrap). As far as I can tell I have to create a separate
'form' element for each tab and use a controller to test across all the tabs' $pristine states in order to determine the overall pristinity (is that a word?).
i.e.
<tab>
<form name="a">...</form>
</tab>
<tab>
<form name="b">...</form>
</tab>
which means I have to test a.$pristine && b.$pristine to determine the overall pristinity. This becomes laborious when there are many tabs involved.
I have tried
<form name="allForm">
<tab>..</tab>
<tab>..</tab>
<tab>..</tab>
</form>
but this doesnt work. I guess the element breaks the form's 'unity'.
Any ideas on how to get a single $pristine (or $dirty) propoerty for a multi-tabbed tabset ?
It seems to be working for me: http://jsfiddle.net/QqBYR/
A change, compared to yours (unless it was a typo) is that the <form> actually wraps the entire <tabset>:
<form name="theForm">
<tabset>
<tab>
<input ng-model="..." />
</tab>
...
</tabset>
</form>