ReactJS, React-Router Getting previous path - animation

I am trying to make a single page application in which I have 3 components : Index, BluePage and GreenPage
I'm trying to use React and React router to switch through them. The layout is as follows:
This view is supposed to be like a sliding page and can be better visualized like this following diagram:
In order to do these transitions, I am currently using ReactCSSTransitionGroup and CSS classes, however it is becoming difficult as the direction the page must animate depends on the page that was being viewed before.
For example, if the BluePage was in view, and the user pressed the "back", button, the Index should move into view from the right.
On the other hand, if GreenPage was originally in view, the Index should move into view from the left.
The Question
How can I use React Router to send the existing path to the next component, so I can animate the components properly?
Should I continue to use ReactCSSTransitionGroup or should I handle animations in the componentWillMount and componentWillUnmount callbacks?
If so, how does adding CSS classes to objects after initial rendering work?
I apologize if these questions seem somewhat novice - I am still a beginner to ReactJS. Thanks for all the help!
If any clarification is necessary, let me know.

I would recommend you to check react-swipeable-views.
In this component, you just need to add all of your views (components) as children of the SwipeableView component. The currently active view is defined by index prop of the SwipeableView. You switch the view with buttons, you simply need to create a state in the main component (App, for example) and update this state in onClick handler. It would look like this:
class MainComponent extends Component {
state = {
index: 0,
}
onBlueButtonClick() {
this.setState({ index: 1 });
}
render() {
return (
<div>
<div onClick={() => this.onBlueButtonClick()}>Click me!<div />
<SwipeableView index={this.state.index}>
<BlueView />
<GreenView />
<RedView />
<SwipeableView />
</div>
);
}
}
Hope it helps! ;)
EDIT: I have added a button in the example to explain how to use this component when there is no swipe effect. This is a React component and not a React Native, so it was made to work on a website, therefore without a swipe. I use it in one of my projects. Here's a GIF of it.

What I would suggest you is tu use swiper.js. Why?
performant (desktop, mobile)
no jquery needed
huge api, with very usefull features for your use case
change slide programmatically: swiper.slideTo(2) or swiper.nextSlide())
Hash/History Navigation: sync between hash and slides
you can disable touch gestures
etc..
Setup
npm install swiper --save
Import
const Swiper = require('swiper');
or
import Swiper from 'swiper';
Usage
see demos with example

Related

How to have the back button in a drawer navigator?

I have a DrawerNavigator as the basic block of my app. The reason is that it should be accessible from all screens. As such, it's also the target for all deep links and will only display some of the items in the actual drawer.
The main page consists of a bottom navigator of stacks, and more entries are also stacks themselves.
The problem is that navigating in the drawer doesn't show any back button as navigating in the stacks would. And it would be nice to have these, just like the back gesture on Android works.
Is this something that exists and if yes, how should it be tackled?
You'll need your own header component in each screen which has a back button. You can use a custom one or one from a component library such as react native paper.
function Home({ navigation }) {
return (
<React.Fragment>
<MyCustomHeader title="Home" onBackPress={navigation.goBack} />
{{
/* screen content */
}}
</React.Fragment>
);
}
Make sure you pass backBehavior: 'history' to createDrawerNavigator.

How to create custom components for Rechart components

Lets say I am creating a bar chart using Recharts, how would i create a custom component for each of the following Recharts components:
XAxis, YAxis, Tooltip, Legend, CartesianGrid, Cell, and Bar
The reason for this s because i am planning to create a chart with a lot of props and wish to separate all the default props and customization in their own individual component for the list component above.
I have tried just putting the CartesianGrid in a react component and the grid will not show
Any ideas?
It seems that you want to wrap the existing Recharts provided components in a custom component for better organization of your code.
This is currently not supported directly by Recharts, as they check for the type of element that you are rendering and if it does not match one of the allowed types it does not get rendered.
For ex:
<LineChart>
<Line></Line>
</LineChart>
would display a line correctly,
But
function MyLine(props) {
return <Line></Line>
}
<LineChart>
<MyLine />
<LineChart>
would not render the line.
This is because, recharts figures out that the MyLine component is not allowed and hence would not be displayed.
This is a big problem as it does not allow us to reuse or compose components.
But there are some workarounds, one of them being calling your custom component as a function directly:
<LineChart>
{
MyLine({})
}
</LineChart>
It also seems like there are no plans to provide such an api in future. All such issues on their github are already closed, without providing a solution.
https://github.com/recharts/recharts/issues/412
https://github.com/recharts/recharts/issues/41
https://github.com/recharts/recharts/issues/1470

Change content view of Laravel layout without page refresh

I've been searching for an hour on how to nagivate within my Laravel website without refreshing the website (page layout), but I couldn't find a proper solution: one that not just loads the HTML, but actually replaces the content view within the layout.
This is my current dashboard:
So when clicking on a menu item within the blue area, I want the red content area to change without page refresh. What would be a scalable solution for this? I'm trying to follow the DRY (Don't repeat yourself) principle as much as possible.
Oh, please don't mark this topic as a clone of other topics as I've seen most of them but without proper solution. Hope anyone can help me out.
Changing a view without page load means we need to use the ajax techology. Vuejs is a frontend frameework the allows us to acomplish that easily with its axios library
I believe you can get this done by using jQuery load function -
$(function () {
$("#menu_option_a").on("click", function () {
$("#dashboard").load("View1.html");
});
$("#menu_option_b").on("click", function () {
$("#dashboard").load("View2.html");
});
});

Nativescript Loading Images

Here is my scenario: On my main view I am loading a list of items. Each item has an imageURL property. I am binding an Image component to the ImageURL property. Everything works well, but the image takes an extra second or two to load during which time the Image component is collapsed. Once the image is loaded, the Image component is displayed properly. This creates an undesirable shift on the page as the image is rendered.
The same images are going to be rendered on 2 other views.
What is the best practice to handle this scenario? I tried loading the base 64 string instead of the image url, which worked, but it slowed down the loading of the initial view significantly.
How can I pre-fetch the images and reuse them as I navigate between the views? I was looking at the image-cache module which seems to be addressing the exact scenario, but the documentation is very vague and the only example I found (https://github.com/telerik/nativescript-sample-cuteness/blob/master/nativescript-sample-cuteness/app/reddit-app-view-model.js) did not really address the same scenario. If I understood the code correctly, this is more about the virtual scrolling. In my case, I will have only 2-3 items, so the scrolling is not really a concern.
I would appreciate any advise.
Thank you.
Have you tried this?
https://github.com/VideoSpike/nativescript-web-image-cache
You will likely want to use a community plugin for this. You can also take a look at this:
https://docs.nativescript.org/cookbook/ui/image-cache
So after some research I came up with a solution that works for me. Here is what I did:
When the app start I created a global variable that contained a list of observable objects
then I made the http call to get all the objects and load them into the global variable
In the view I displayed the image as (the image is part of a Repeater item template):
<Image loaded="imageLoaded" />
in the js file I handled the imageLoaded events as:
var imageSource = require("image-source");
function imageLoaded(args) {
var img = args.object;
var bc = img.bindingContext;
if (bc.Loaded) {
img.imageSource = bc.ImageSource;
} else {
imageSource.fromUrl(bc.ImageURL).then(function (iSource) {
img.imageSource = iSource;
bc.set('ImageSource', iSource);
bc.set('Loaded', true);
});
}
}
So, after the initial load I am saving the imageSource as part of the global variable and on every other page I am getting it from there with the fallback of loading it from the URL is the image source is not available for this item.
I know this may raise some concerns about the amount of memory I am using to store the images, but since in my case, I am talking about no more than 2-3 images, I thought that this approach would not cause any memory issues.
I would love to hear any feedback on how to make this approach more efficient or if there is a better approach altogether.
You could use the nativescript-fresco plugin-in. It is an {N} plugin that is wrapping the popular Fresco library for managing images on Android. The plugin exposes functionality like: setting fade-in length, placehdler images, error images (when download is unsuccessful), corner rounding, dinamic sizing via aspect ration etc. for the full list of the advanced attributes you can refer this section of the readme. Also the plugin exposes some useful events that you can use to add custom logic when images are being retrieved from remote source.
In order to use the plugin simply initialize it in the onLaunch event of the application and call the .initialize() function:
var application = require("application");
var fresco = require("nativescript-fresco");
if (application.android) {
application.onLaunch = function (intent) {
fresco.initialize();
};
}
after that simply place the FrescoDrawee somewhere in your page and set its imageUri:
<Page
xmlns="http://www.nativescript.org/tns.xsd"
xmlns:nativescript-fresco="nativescript-fresco">
<nativescript-fresco:FrescoDrawee width="250" height="250"
imageUri="<uri-to-a-photo-from-the-web-or-a-local-resource>"/>
</Page>

The view area of ckEditor sometimes shows empty at the start

I am using the following directive to create a ckEditor view. There are other lines to the directive to save the data but these are not included as saving always works for me.
app.directive('ckEditor', [function () {
return {
require: '?ngModel',
link: function ($scope, elm, attr, ngModel) {
var ck = ck = CKEDITOR.replace(elm[0]);
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
setTimeout(function () {
ck.setData(ngModel.$modelValue);
}, 1000);
}; }
};
}])
The window appears but almost always the first time around it is empty. Then after clicking the [SOURCE] button to show the source and clicking it again the window is populated with data.
I'm very sure that the ck.setData works as I tried a ck.getData and then logged the output to the console. However it seems like ck.setData does not make the data visible at the start.
Is there some way to force the view window contents to appear?
You can call render on the model at any time and it will simply do whatever you've told it to do. In your case, calling ngModel.$render() will grab the $modelValue and pass it to ck.setData(). Angular will automatically call $render whenever it needs to during its digest cycle (i.e. whenever it notices that the model has been updated). However, I have noticed that there are times when Angular doesn't update properly, especially in instances where the $modelValue is set prior to the directive being compiled.
So, you can simply call ngModel.$render() when your modal object is set. The only problem with that is you have to have access to the ngModel object to do that, which you don't have in your controller. My suggestion would be to do the following:
In your controller:
$scope.editRow = function (row, entityType) {
$scope.modal.data = row;
$scope.modal.visible = true;
...
...
// trigger event after $scope.modal is set
$scope.$emit('modalObjectSet', $scope.modal); //passing $scope.modal is optional
}
In your directive:
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
};
scope.$on('modalObjectSet', function(e, modalData){
// force a call to render
ngModel.$render();
});
Its not a particularly clean solution, but it should allow you to call $render whenever you need to. I hope that helps.
UPDATE: (after your update)
I wasn't aware that your controllers were nested. This can get really icky in Angular, but I'll try to provide a few possible solutions (given that I'm not able to see all your code and project layout). Scope events (as noted here) are specific to the nesting of the scope and only emit events to child scopes. Because of that, I would suggest trying one of the three following solutions (listed in order of my personal preference):
1) Reorganize your code to have a cleaner layout (less nesting of controllers) so that your scopes are direct decendants (rather than sibling controllers).
2) I'm going to assume that 1) wasn't possible. Next I would try to use the $scope.$broadcast() function. The specs for that are listed here as well. The difference between $emit and $broadcast is that $emit only sends event to child $scopes, while $broadcast will send events to both parent and child scopes.
3) Forget using $scope events in angular and just use generic javascript events (using a framework such as jQuery or even just roll your own as in the example here)
There's a fairly simple answer to the question. I checked the DOM and found out the data was getting loaded in fact all of the time. However it was not displaying in the Chrome browser. So the problem is more of a display issue with ckEditor. Strange solution seems to be to do a resize of the ckEditor window which then makes the text visible.
This is a strange issue with ckeditor when your ckeditor is hidden by default. Trying to show the editor has a 30% chance of the editor being uneditable and the editor data is cleared. If you are trying to hide/show your editor, use a css trick like position:absolute;left-9999px; to hide the editor and just return it back by css. This way, the ckeditor is not being removed in the DOM but is just positioned elsewhere.
Use this java script code that is very simple and effective.Note editor1 is my textarea id
<script>
$(function () {
CKEDITOR.timestamp= new Date();
CKEDITOR.replace('editor1');
});
</script>
Second way In controller ,when your query is fetch data from database then use th
is code after .success(function().
$http.get(url).success(function(){
CKEDITOR.replace('editor1');
});
I know, that this thread is dead for a year, but I got the same problem and I found another (still ugly) solution to this problem:
instance.setData(html, function(){
instance.setData(html);
});

Resources