Is it possible to mix two GraphQL queries into one query? - javascript

I am using Gatsby as a frontend to a WordPress backend. I have successfully fetched the menu items but I now need to link them to the pages I have created. I have added the Menu Links in my Gatsbyconfig.js but I have no idea on how I can go about mapping it to the menu items at the same time as the menu itself. It ends up contradicting each other. Is this possible to do? I am quite new at graphQL. Never touched it till this project. Below is the GraphQl Query
{
allWpMenuItem(filter: {menu: {node: {name: {eq: "Navigation Menu"}}}}) {
edges {
node {
label
}
}
}
site {
siteMetadata {
title
menuLinks {
name
link
}
}
}
}
The label holds the name for each menu and the link holds the link to the pages I have created. I am trying to fix this into this bit of code
<div>
{props.allWpMenuItem.edges.map(edge =>(
<a href="#" key={edge.node.label}>
{edge.node.label}
</a>
))}
</div>
I am trying to query the menu links change the anchor tag to the link item and then point it to the menu link.

The short answer is that you can't, natively each query is a separate entity. However, you can combine queries using createResolvers, for further details check: https://github.com/gatsbyjs/gatsby/discussions/28275 (thanks LekoArts for the feedback).
However, you have a few approaches to bypass this limitation. Given that each query is transformed into a standalone JavaScript object, you can always manipulate them using native JavaScript filtering or doing whatever you need. The idea is to create an empty object and populate it with links and labels, in a single loop or using two different, then, in your component, iterate through this object instead of through the props like you are doing now.
I can't create a minimal example without knowing the internal structure or without knowing what's inside menuLinks.name.
By the way, if you are using internal navigation I would hardly suggest using <Link> component, among other things, using the #reach/router (extended from React's router) will only render the necessary parts of each component, creating smoother navigation than using native anchor tag, what will refresh all the page.

Related

React Side bar - to navigate similar to link provided

I am new to React JS and would like few ideas regarding implementing the side navigation.
We have Side Nav currently which gets generated from an API response in below structure.
A section may or may not have a subsection. Also, Subsection may or may not have a sub of sub-section. This can be infinite.
abc-SECTION
abcdef-SUB-SECTION
woirlew-SUB-SUB-SECTION
ABCDWER-SUB-SECTION
ABCDXDC
WERLLWWR-SUB-SUB-SECTION
xyz-SECTION
XYZSERF-SUB-SECTION
XYZlJIO-SUB-SECTION
owe-SECTION
abcdef-SUB-SECTION
ABCDWER-SUB-SECTION
slfjl-SUB-SECTION
We want to keep the tree structure as above but want to our tree structure to behave something similar to below link.
https://www.hindustantimes.com/interactives/aap-government-two-years-report-card/
We already have a side bar rendering implemented using recursive function. I am looking for scrolling behaviour.
Any guidance would be appreciated. What would be the good way to start with?
To create sidebar can create kind of recursive Component in reactjs.
class Tree extends Component {
render() {
return {
<div>
{this.props.children.map((child) => (
<div key={child.key}>
<span>{child.name}</span>
{child.children && <Tree children={child.children} />}
</div>
))}
</div>
}
}
}
In React to render a list you can have a separate function that takes a data structure as an input such as array or object and recursively calls itself to generate a UL, LI structure. Check this link out for recursively iterateing through an nested array of objects
For the scrolling behaviour you can usive javascript onClick event handler and window.scrollTop to calculate and scroll smoothly to that place alternatively theres a light-weight library for that behaviour Click here to Check it out

Switching from hash-based nav to HTML5 History API

I'm trying to figure out how to use the History API for my webpage. Currently, it's a simple page where the navbar toggles content visibility on click by changing an ID's display to none or block.
I'd like to switch over to the History API because of the browser back button memory, but all of the examples I'm finding use AJAX to load data from a separate file on click. My pages aren't big enough to warrant asynchronous loading.
Is there any way for regular URLs to trigger CSS property changes the way that hashes do?
No, CSS can only react to :target via the hash component of the URL. However you can still take advantage of the History API if you want to; you'll just need a little bit of additional javascript. For example you could a data-target attribute to the <html> element which changes depending on the URL, and your css could then react to this through something like:
[data-target="home"] #home-page { display: block; }
The History API allows you to store some state with each entry, so you could use this to store the target identifier and then retrieve this again in your "popstate" handler - e.g.
history.pushState({ target: 'home' }, '', '/home')
document.documentElement.dataset.target = 'home'
window.addEventListener('popstate', function (e) {
document.documentElement.dataset.target = e.state.target
})

How to observe multiple states in a handlebar template from an ember controller or component

I'm new to ember and am struggeling with the typical "how would one do that"-Problem. What I've got is fairly simple and I know how to do it, but my way is so complicated that I do not think it's correct.
The case:
<ul>
<li>{{link-to top-level}}</li>
<li>{{link-to another-top-level</li>
<ul class="submenu">
<li>{{link-to submenu</li>
</ul>
</ul>
What should happen is:
When a route is clicked, the corresponding list element should become active.
When a submenu is clicked the corresponding upper ul-element should get the class open
It's a fairly simple case with jQuery, but I understand that this is not scalable and abstracted and stuff.
Therefore I started with this approach:
Create a controller / template construct for the entire navigation to handle it's state (there are some other things I need to check as well, so it came in handy).
since ember adds the active class to the anchor tag I created a component to observe that:
Like:
export default Ember.Component.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('childViews').anyBy('active');
}.property('childViews.#each.active')
});
Replacing the li elements with {{linked-list}} does indeed work.
But what next? Do I need to add another component to watch the component to watch the build in behaviour of active links? Do I have to write dedicated MVC-Classes for all the DOM Elements?
There has to be a simpler way, I think. I already created a whole lotta files for such a simple behaviour that I'm thinking I'm totally on the wrong track.
My gut feeling is: That is view logic and the view should just observe a few states in the template and that's it.
What's the leanest approach to the problem?
I don't know if I understand your question right, but why you want to add the class open to the corresponding upper element? It automatically get active assigned. And with correct CSS it should work as expected.
I have created a small example demonstrating what I mean. Please have a look and let me know, if that's the solution for you or what's your problem with this solution.
http://emberjs.jsbin.com/wifusosadega/7/edit
EDIT
Here is a Bootstrap flavored version: http://emberjs.jsbin.com/wifusosadega/9/edit .

Change browser url without page reloading with ajax request

So I'm following this tutorial:
http://www.tinywall.info/2012/02/change-browser-url-without-page-reload-refresh-with-ajax-request-using-javascript-html5-history-api-php-jquery-like-facebook-github-navigation-menu.html
My goal is to load the actual content of my views and change the browsers URL without reloading the page. However, because I'm using CodeIgniter as a framework of my application, I can't get it to work properly. I have a controller where I'm loading all of my Dashboard's views, ones I want display inside my div called content_container.
The problem is that every time I click another anchor tag to get different view to load through ajax request, it adds another "dashboard" -in my url and of course it doesn't display the view after that. So after couple clicks, the URL would look something like this: "dashboard/dashboard/dashboard/profile". I've tried to split the URL with Javascript, but that didn't help me.
One solution would be to create single controller for each view, but I consider it as a bad practice and the code is a lot more cleaner with just one controller to handle all the views.
Here's the controller:
<?php
class Dashboard extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->output->nocache();
$this->load->model('subject_model');
$this->load->model('user_model');
}
public function index()
{
$this->load->view('header');
$this->load->view('dashboard');
$this->load->view('footer');
}
public function users()
{
$data['users'] = $this->user_model->getUsers();
$this->load->view('staff_users', $data);
}
public function lomake()
{
$this->load->view('lomake');
}
public function profile()
{
$data['userinfo'] = $this->user_model->getUserInformationById($this->session->userdata('user_id'));
$this->load->view('myprofile', $data);
}
public function subjects()
{
$this->load->view('subjects');
}
}
?>
And here's my dashboard view (part of it):
<aside id="left_control_panel">
<ul id="left_control_links">
<li>
Home
</li>
<li>
Subjects
<span class="list_total_count"><?=$total_subjects?></span>
</li>
<li>
Query
</li>
<?php if($this->session->userdata('user_type') == 'admin'):?>
<span class="left_control_heading">User management</span>
<li>
Users
<span class="list_total_count"><?=$total_users?></span>
</li>
<li>
<a class="add_user" href="add_user">Add User</a>
</li>
<?php endif;?>
<span class="left_control_heading">Account management</span>
<li>
My Profile
</li>
<li>
Sign Out
</li>
</ul>
</aside> <!-- end of left_control_panel -->
<div id="wrapper_loggedin">
<div class="content_container">
<! -- I will display all the data from different views in here -->
</div>
</div> <!-- end of wrapper_loggedin -->
And finally the JS part which can also be found in the tutorial:
$(function(){
$("a[rel='tab']").click(function(e){
//e.preventDefault();
pageurl = $(this).attr('href');
$.ajax({url:pageurl+'?rel=tab',success: function(data){
$('.content_container').html(data);
}});
//to change the browser URL to 'pageurl'
if(pageurl!=window.location){
window.history.pushState({path:pageurl},'',pageurl);
}
return false;
});
});
/* the below code is to override back button to get the ajax content without reload*/
$(window).bind('popstate', function() {
$.ajax({url:location.pathname+'?rel=tab',success: function(data){
$('.content_container').html(data);
}});
});
Application/config/routes.php
$route['dashboard'] = 'dashboard/index';
$route['dashboard/(:any)'] = 'dashboard/$1';
well, with my specific situation I had thousands of products organized in categories and sub categories. Well..thats a ton of urls and controllers to write. so what i did was make a category template, a sub category template and a product page template. then made routes like below in my application/config/routes.php file:
$route['products'] = 'products/index';
//so i know now they are on a category page and $1 is the name of the category.
//i can go query my db and get all subcategorys and the products under each now.
$route['products/(:any)'] = 'products/category/$1';
//the 1 and 2 here are category and subcategory from the url. so i know from this to
//use these in my query to grab all products in this category and subcategory.
$route['products/(:any)/(:any)'] = 'products/subcategory/$1/$2';
//i know this is gonna be a product page. and i know the category, the sub category and the product name. in this case all i really need is the product name since there is only one product with that name.
$route['products/(:any)/(:any)/(:any)'] = 'products/details/$1/$2/$3';
in your situation you can do the same. use your urls, your taking the time to build them so use them. in javascript you can send them back to your controllers via 'window.location.pathname'; all you have to do is split it up and you can use the same mentality to load a page and know exactly where you are at.
Also, in your ajax url property make sure your url is either an absolute url, or it references the root first. I think i know what your issue is. you are using a url like "users/dashboard" in your url property when it should be "/users/dashboard" you need to always go to the root and get the controller, otherwise it uses the url and will always take on the "users/dashboard" to the current url you are on. So if you are on "users/dashboard" and go load it again, your actually telling it to load "/users/dashboard/users/dashboard" and this becomes an infinite loop. Just put a backslash in front of your url and it will always reference the root.
I just did this very same thing. The way I did it was first make a dynamic route to always point to the same controller. $route['products/(:any)/(:any)/(:any)'] = 'products/details/$1/$2/$3'; etc. then anytime your page is loaded via a url (if someone puts in a specific url) you will still get content (bookmarks still work, you can send specific urls to people etc). Then what I did was every link that changed content also applied a data attribute to build the url out, i would also use those to pass back to the same controller. That controller also checks if the request is coming from an ajax request or not...if it is, you just load the page content...if it isnt then load the full template. its really not that hard and you actually almost have what i have. I think you are over thinking it. But the first thing i would do is make sure going to every page with the url works first. then try to get the ajax part working. The key is to detect if the request is coming from ajax or not within your controller. Then you can differentiate the two.
Also, I would strongly recommend you reading the user guide. The routes are usually one of the first thing you should cover when you start building projects with Codeigniter.
http://ellislab.com/codeigniter/user-guide/general/routing.html
Answering your question on the core controller. The answer is yes, you create a controller inside your core folder. It has to have a specific name. In your application/config/config.php file you should have:
$config['subclass_prefix'] = 'MY_';
This defines your prefix to any extended core controllers, models or system classes. Most Codeigniter system classes can be extended and you can overwrite properties (variables) and methods (functions). In your case you would drop a file called MY_Controller.php in your application/core folder. In this controller you would approach it like any other controller you write with the idea to not have to keep rewriting the same code over and over again, or to change the way the default Controller operates. You should read up on how a php class is suppose to work and the purpose of using them. Codeigniter doesn't really use them the way that you are suppose to use a class, but they approached it with the MVC approach. Usually, a class is referenced to as an object. Think of a class as a Bear. A bear has weight, age, length, color, height. All of these are called "properties". A bear can also eat, drink, and hunt. Each of these are called "methods". A more detailed version of a bear would be a polar bear, grisly bear or panda bear. These could be children of the bear object (they would extend the Bear object). Any child object inherits its parents properties and methods. But their values and actions could differ. The polar bear is a different color, size, height than the panda bear but it still eats, drinks, and hunts. Some properties and methods might not change, so there is no reason to rewrite those in the child classes. So in your case, the core controller can handle things that every page does. It can verify sessions, track a users activity, define global error messages etc. Ive even gone so far as to create a method in my core controller that loads my template pieces together (header, footer, sidebar, content) so i didn't have to keep stacking $this->load->view() when i was loading pieces of my template. All I had to do was pass the content and data that needed to be passed and it loaded my template everywhere. You also need to understand how the __construct works. You can think of the __construct as a function that always runs first before your page loads. so by defining a construct in your core controller you can then fill in data automatically. Browse these links as they go into a deeper explanation on how to use these features and shows examples.
http://ellislab.com/codeigniter/user-guide/general/core_classes.html
http://www.php.net/manual/en/language.oop5.php
Please give me a up vote if this guided you in the right direction :) Im trying to build up my points and profile and eventually link my account up to my website so it proves my plethora of php & codeigniter knowledge to any future employees.

Help with Dojo Drag & Drop

Hi I am trying to implement some drag and drop functionality into a project but am having a bit of difficulty with a few aspects. One of the problems I am having is with the creation of a custom avatar, I am able to achieve a custom avatar but have to cheat slightly and hide some elements with CSS.
Below is a snippet of my code not the entire code, I have required all necessary pacakges etc.
dojo.query(".canDrag").forEach(function(node, index, nodelist){
var createSource = new dojo.dnd.Source(
node, {copyOnly: true, creator: createAvatar}
);
function createAvatar(item, hint) {
var node = dojo.doc.createElement("span");
dojo.addClass(node, "avatarStyle");
if ( hint == "avatar" ) {
var dHtml = item;
console.log("trying " + dHtml);
node.innerHTML = item;
}
else {
console.log("if this show remove redudant call");
}
return {node: node, data: item, type: "product", copyOnly: true};
};
Ok so as you can see I create my DnD source then give it a custom creator where I attempt to build my own custom Avatar. The actyual draggable markup is below:
<div class="canDrag panelLeft">
<div class="dojoDndItem" dndType="product" title="digitalCamera" id="12345">
<h3 class="productTitle">Samsung ES71</h3>
<p class="productType">Compact Digital Camera</p>
<img src="img/small_Cam.png" class="imgLMargin" alt="Samsung ES71"/>
<div class="dragHandle">
</div>
</div>
</div>
Rather than append the entire div from canDrag and down I would like to grab different elements such as the image and .product title and just display those. If any one has any ideas I thank you in advance also if my question has not been clear enough I can try to rephrase.
Cheers
CSS should be fine. Otherwise, you can either use the dndData attribute for your items, or add the items manually to your DnD source object.
When using dojoDndItem class, Dojo expects the visualization of the avatar to be already resolved in the markup itself. That's why it passes the inner HTML as the item data. This is for the most simple and common case, when you would not use a custom creator. I think using CSS to customize the avatar is fine. Even if you don't use a custom creator to set the avatarStyle class, you can take advantage of the fact that Dojo puts the avatar inside its own container marked with the class dojoDndAvatar (or dojoDndAvatarItem). Take a look at the source at dojo/dnd/Avatar.js.
If you still want to use a custom creator, you have a couple of options:
Add a dndData attribute to your items. In that case, that's what gets passed to the creator function as the item parameter. It can be anything, and you can use that to further customize the avatar. Eg. you could serialize a JSON object and dynamically create the avatar from that object, or you could set it to a unique id and then use dojo.query() to access the nodes below it.
Remove the items entirely add them programmatically with the insertNodes() method. In that case, your creator function must implement both the case for the avatar and the case for the actual item.
It doesn't address your question in particular, but here's an excellent Dojo DnD tutorial.
The Dojo reference guide is also helpful, once you understand what's happening. And of course, use the source Luke!

Categories

Resources