Loading Jquery tab UI dynamically in angular - javascript

I am using jquery-ui tabs plugin .
The trouble I am having is I load the tabs on a row click(table in html) and thus the tabs length can be dynamic on every row user clicks and also I built the tabs in HTML using angular directives
This is how I am create the tabs in angular
<div class="modal-body">
<div id='tabs'>
<ul >
<li ng-repeat="row in tabs.row">
{{row.Tab}}
</li>
</ul>
<div ng-repeat="row in tabs.row" id="tabs-{{$index + 2}}">
{{row.Tab}}
</div>
</div>
</div>
Also I am a modal window , the trouble is the $( "#tabs" ).tabs(); function doesn't sync with ng-repeat I wait it some time when my model is loaded and then call it ,like so
jsonData (In XML form for simplicity) :
<data>
<row>
<Tab>General</Tab>
</row>
<row>
<Tab>Locations</Tab>
</row>
<row>
<Tab>Treatment</Tab>
</row>
<row>
<Tab>Training</Tab>
</row>
<row>
<Tab>Facilities</Tab>
</row>
<row>
<Tab>Equipment</Tab>
</row>
<row>
<Tab>Physicians</Tab>
</row>
<row>
<Tab>People</Tab>
</row>
</data>
Saving data:
$scope.tabs=jsonData;//save to model
r =setTimeout(initTabs,500); //give some time to modal to save data
function initTabs(){
$( "#tabs" ).tabs();
console.log('timerCalled');
r=clearTimeout();
}
Now this works for the firs time , but any subsequent clicks to reset the tab results in the tabs having only one tab and are obscure .
Is there a way I can do this , I am thinking of someone resetting the classes added by #id.tabs() functionality but looking for a easier way .

I figured out I can revert changes done by #selector.tabs() by using #selector.destroy()
Only catch is I have find a way if I have used #selector.tabs or not ,one way is:
if(selector.data("ui-tabs"))
Here is my re initialization code again :
function initTabs(){
if ($( "#tabs2" ).data("ui-tabs")) {
$( "#tabs2" ).tabs( "destroy" );
}
$( "#tabs2" ).tabs();
console.log('timer');
r=clearTimeout();
}

Related

Ant Design: How to remove trailing end gutter on each Row

I am using antd's Row and Col components to create a responsive grid. However, when a column wraps underneath due to a breakpoint, there is some clear whitespace (pretty sure caused by gutters) at the end of the line above a shown bellow:
The textfields belong in one row, and the button in another. There is a gutter next to each text field that I want to get rid of so they properly fit the parent's width.
How would I go about doing that? Quick demonstration:
<Row>
<Col xs={{span: 24}}>
<Row>
<Col xs={{span: 24}} ...>
<Input/>
</Col>
<Col xs={{span: 24}} ...>
<Input/>
</Col>
<Col xs={{span: 24}} ...>
<DateRangerPicker/>
</Col>
</Row>
</Col>
<Col xs={{span: 24}}>
<Button/>
</Col>
</Row>
It has gutter attribute, but btw it is 0 by default!

How can I componentize TextFields into a function rather than writing multiple TextFeilds?

There is a lot to read here, but there is no other way to explain the issue I have.
I have four files, App.js, Intakes.js, IntakeDetails.js and Sizing.js. I start on the Intakes page where the user is presented with a table of data. The user clicks on a row and is taken to IntakeDetails. In IntakeDetails, there are four MUI tabs, one of which is Sizing.
The user never actually goes to a Sizing page. They only get to IntakeDetails. From IntakeDetails, the user can view, edit, and create data based on what tab they are in. If the user wants to create or update Sizing data, they navigate to the sizing tab and click the edit icon on the row of their choice from the Sizing table. The Dialog then pops up and its TextFields are populated with the data from the row the user clicked.
Sizing.js is 600+ lines long. 211 lines in this file are taken up by the MUI dialog which displays the data from the table row the user has clicked. The dialog is so long because of 19 TextFields. I want to make a short function with a parameter for id, value and label. This way I wont need to have lots of multiline TextFields. All of the TextFields in the Dialog take up 8 lines. With a function, this could be just one or two lines.
I have made a function to shorten the file previously, but it introduces a new problem. If I have a TextField that is populated with the word 'Hello', and I edit it, the Dialog disappears, reappears, and focus is lost on the TextField I edited, but, the change I made is persistent. I can only enter or remove one character at a time before having to click on the TextField again to enter another. I can copy and paste full words and sentences at once, but again the Dialog disappears and comes back.
I can't use .map because my data is not divided into groups or objects. It is all one object and needs to be presented in the dialog in a specific order, which is why they are hardcoded. When I type in a TextField, there is a long delay between the time I press a key on the keyboard and the time the character appears in the TextField. This delay gets longer when I type faster.
The return in IntakeDetails is here:
import Sizing from "./Sizing";
...
return (
<div class="aspectwrapper">
<div class="content">
<Container>
<Paper>
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs value={value} onChange={handleChange}>
<Tab label="Intake Details" {...a11yProps(0)} />
<Tab label="Sizing" {...a11yProps(1)} />
</Tabs>
</Box>
<TabPanel value={value} index={0}>
** Intake Details Stuff **
</TabPanel>
<TabPanel value={value} index={1}>
<Sizing />
</TabPanel>
</Box>
</Paper>
</Container>
</div>
</div>
)
The return in Sizing. There are 19 TextFields, all structured as seen below. There are also buttons in a <DialogActions> tag which I have not included here.
const onTextChange = (e) => {
const id = e.target.id;
var value = e.target.value;
setSingleSizing({ ...singleSizing, [id]: value });
};
...
return(
<div id="sizing-container">
<Dialog open={open} onClose={handleClose} maxWidth={"xl"}>
<DialogTitle id="form-dialog-title">Edit estimation</DialogTitle>
<DialogContent>
<Box>
<TextField
id="SizingComments"
value={singleSizing?.SizingComments}
label={"Estimation Comments"}
onChange={onTextChange}
variant="outlined"
style={{ margin: "1em", minHeight: "1em", minWidth: "15em" }}
/>
</Box>
</Box>
</DialogContent>
</Dialog>
</div>
)

Best way to change CSS in multiple components of the same component in React

I have a component that i'm using 3 times with different data which I am able to complete with the following code;
<div>
<Container className="mt-5">
<Row>
{author_data.map((authors) => {
return (
<Col key={authors.id} className="pe-5 ps-5">
<Author
key={authors.id}
image={authors.image}
author={authors.author}
description={authors.description}
handleClick={(author) => setAuthor(author)}
/>
</Col>
);
})}
</Row>
</Container>
</div>
);
However Im looking to change the CSS on each component once I click on one of the Author components. something like the below using native JS.
document.getElementById("author1").classList.add("addGrayScale");
document.getElementById("author2").classList.add("addGrayScale");
document.getElementById("author3").classList.remove("addGrayScale");
I have used the useState and useContext hooks but I can't seem to get it to work because the Author component will receive the same props. Should I create separate components for each Author? or is there another way to do this.

Next/router nothing happens when browser’s back button click

I don't understand why, when I click on browser’s back button my page doesn't reload.
I have a catalog component inside /pages/index.js which is my home page, a dynamic route to navigate to the products /pages/books/[name].js
This is the Link I use to go to the products pages :
<div className="container-cat">
{products.map((_product) => (
<Card id="lien" key={_product.id} alt="book" className="catalogue">
<Link href='/books/[name]' as={`/books/${_product.name}`}>
<a>
<Card.Body>
<Card.Img variant="top" src={getStrapiMedia(_product.grid_pic.url)} width="200px" />
<Card.Title>{_product.name}<br />{_product.author}<br />{_product.price} €</Card.Title>
</Card.Body>
</a>
</Link>
</Card>
))
}
</div>
I don't know what else to put here ...
I change my routes, putting the catalog component as the index.js of the /pages/books/
I can't really explain why, but it works

Riot.js: Reusing children tag names within different parent tags

I'm working on a small ui project. So I developed 'form-accordion' tag that is used in following way:
<form-accordion>
<panel label='panel 1'>
...
</panel>
<panel label='panel 2'>
...
</panel>
</form-accordion>
Now I want to define another tag 'form-tabs' that I want to use in following way:
<form-tabs>
<panel label='panel 1'>
...
</panel>
<panel label='panel 2'>
...
</panel>
</form-tabs>
My question is: How to define two different tags 'panel' that will render different way under different parent tags.
I think there are different ways of doing this, but basically you will define a script inside your subtag and that script receive something that indicates the change, after that, the script of panel.tag will handle your content. One way to write that code:
file: panel.tag
<panel>
<div>
Your HTML here
</div>
<script>
this.on('mount', function(){
//write your code to handle content here
if(opts.type == 1)
{
// do something
}
else if(opts.type == 2)
{
// do something else
}
});
</script>
<style>
/* CSS class of that tag */
</style>
</panel>
So when you call that tag you send something to change your content, like attribute:
file: form-accordion.tag
<form-accordion>
<panel type="1">
</panel>
</form-accordion>
file: form-tabs.tag
<form-tabs>
<panel type="2">
</panel>
</form-tabs>
Another way is use better riot features like:
file: panel.tag
<panel>
<div>
<div if={opts.type == 1}>
Panel 1
</div>
<div if={opts.type == 2}>
Panel 2
</div>
</div>
<script>
//
</script>
<style>
/* CSS class of that tag */
</style>
</panel>
Edit
I read again your question and perhaps simple approach fits better to your needs, that code just write your label on HTML of panel.tag:
file: panel.tag
<panel>
<div>
{ opts.label }
</div>
</panel>
Hey I think to optimize your code, rather than call the panel tag multiple times (depending on the number of panel tags you want to see), you could create a simple loop using riot's each keyword to create the number of panels you want to use ... as shown below for the form-accordion & form-tabs tags. We can pass the panelNum in the loop as part of the tags opts array in an arg you called label
<form-accordion>
<div each={panelNum in NumOfPanelsNeeded}>
<panel label={panelNum}> ... </panel>
</div>
</form-accordion>
<form-tabs>
<div each={panelNum in NumOfPanelsNeeded}>
<panel label={panelNum}> ... </panel>
</div>
</form-tabs>
Then, within the famous panel tag, we can retrieve this label arg from the opts array and then finally display it in the tags html.
<panel>
<div>panel { label }</div>
<script>
this.label = opts.label
</script>
</panel>
Simple as that! ;)
If you need help figuring out how to add event handlers from child to parent in javascript, let me know.

Categories

Resources