SystemSeed.com: 10 Tips for a Successful Web Development Project for Charities, Nonprofits and NGOs
Essential strategies for a seamless and effective nonprofit web development experience
Tamsin Fox-Davies Tue, 02/07/2023 - 09:53Essential strategies for a seamless and effective nonprofit web development experience
Tamsin Fox-Davies Tue, 02/07/2023 - 09:53Interactive web experiences provide a more engaging and enjoyable experience for users. It leads to increased user satisfaction and a positive perception of a website. For example, a form that provides instant feedback and validation, rather than making the user wait for a page refresh, can significantly improve the user experience.
JavaScript plays an important role in Drupal by providing the means to create dynamic and interactive experiences for users on the frontend of a Drupal website. It enables developers to modify the behavior of certain elements on a page, such as forms, links, or any other DOM elements, without having to refresh the entire page. Drupal Behaviors are JavaScript functions that get executed when specific events occur on a page. Behaviors make it easy for developers to maintain and upgrade a site as they don’t need to change any underlying HTML code. Find out all you wanted to know about Drupal Behaviors in the article.
Drupal.behaviors is an object inside the Javascript structure in Drupal, which allows us to attach functions to be executed at certain times during the execution of the application. It is called when the DOM is fully loaded, but these behaviors can be called again. Drupal’s official JavaScript documentation suggests that modules should implement JavaScript by attaching logic to Drupal.behaviors.
The advantage of Behaviors is that they are automatically re-applied to any content that is loaded through AJAX. They can be called at any time with a context that represents new additions or changes to the DOM. This is better than $(document).ready() or document DOMContentLoaded where the code is just run once.
Drupal behaviors are not always the perfect solution for writing Javascript in Drupal. In some cases, as stated below Drupal behaviors are not needed at all!
In this code, we are adding a click event listener to the .views-row class which calculates the number of times we are clicking on this row. But it is added only once to the elements which come in the DOM during the initial page load. After clicking on Load More and loading more items, the click listener does not work on the newly loaded items.
// No Drupal Behaviors
(function () {
let header = document.querySelector(".food-list-header");
if (header) {
let greatFoodSpan = document.createElement("span");
greatFoodSpan.textContent = "Get ready for great food!!!!!!";
header.append(greatFoodSpan);
}
// Add the event listener for each click on the food
let foods = document.querySelectorAll(".views-row");
foods.forEach((food) => {
food.addEventListener("click", () => {
let foodCounter = food.querySelector(".food-click-counter");
let timesClicked = parseInt(foodCounter.textContent.trim());
foodCounter.textContent = ++timesClicked;
});
});
})();
Answer: Using the attach method
Things to remember:
After adding Drupal Behaviors, the code looks something like this.
(function (Drupal) {
Drupal.behaviors.exampleBehaviour1 = {
attach: (context, settings) => {
// Add a delicious text to the top of the document
let header = document.querySelector(".food-list-header");
// jQuery Equivalent
// $(".food-list-header");
if (header) {
let greatFoodSpan = document.createElement("span");
greatFoodSpan.textContent = "Get ready for great food!!!!!!";
header.append(greatFoodSpan);
}
// Add the event listener for each click on the food
let foods = document.querySelectorAll(".views-row");
foods.forEach((food) => {
food.addEventListener("click", () => {
let foodCounter = food.querySelector(".food-click-counter");
let timesClicked = parseInt(foodCounter.textContent.trim());
foodCounter.textContent = ++timesClicked;
});
});
},
};
})(Drupal);
But something odd appears in the top when we click on Load More:
This is because Drupal behavior is called a lot of times and subsequently we get some unintended behavior.
The previous problem can be solved by using the context parameter that is provided by Drupal Behaviors. In this case, the first time the page loads, we get the whole HTML Document as context and that’s when we attach the header. For further operations, it will be the part of the code which is affected by Drupal Behaviors and hence that part of the code is safely controlled.
(function (Drupal) {
Drupal.behaviors.exampleBehaviour2 = {
attach: (context, settings) => {
// Add a delicious text to the top of the document.
// The context parameter now can be used for adding
// certain functionality which removes unwanted repeatability
let header = context.querySelector(".food-list-header");
// jQuery Equivalent
// $(".food-list-header", context);
if (header) {
let greatFoodSpan = document.createElement("span");
greatFoodSpan.textContent = "Get ready for great food!!!!!!";
header.append(greatFoodSpan);
}
// Add the event listener for each click on the food
let foods = context.querySelectorAll(".views-row");
foods.forEach((food) => {
food.addEventListener("click", () => {
let foodCounter = food.querySelector(".food-click-counter");
let timesClicked = parseInt(foodCounter.textContent.trim());
foodCounter.textContent = ++timesClicked;
});
});
},
};
})(Drupal);
Again there is some odd behavior when we click on Load More. The food items which were initially loaded work fine. But After clicking on Load More, the new items get the click listener and work normally. But the initially loaded items get the listener attached again and clicking on them calls the click event more than once!
(function (Drupal, once) {
Drupal.behaviors.exampleBehaviour3 = {
attach: (context, settings) => {
once("food-header-initialized", ".food-list-header", context).forEach(
(header) => {
let greatFoodSpan = document.createElement("span");
greatFoodSpan.textContent = "Get ready for great food!!!!!!";
header.append(greatFoodSpan);
}
);
// jQuery Equivalent
// $(".food-list-header", context).once("food-header-initialized", function (header) {
//
// });
// Add the event listener for each click on the food
once("food-initialized", ".views-row", context).forEach((food) => {
food.addEventListener("click", () => {
let foodCounter = food.querySelector(".food-click-counter");
let timesClicked = parseInt(foodCounter.textContent.trim());
foodCounter.textContent = ++timesClicked;
});
});
},
};
})(Drupal, once);
Now everything works as intended. We get a data-once attribute to the elements where the event listeners are attached and newly loaded elements and previously loaded elements function properly.
The Detach method acts like an anti-hero (not evil), removing whatever we did in the attach method. Any code in the detach method will be called whenever content is removed from the DOM. This helps us to clean up our application. For example, Detach method enables us to remove unwanted event listeners which consume resources like a continuous polling situation.
Assume that we have an ajax form to fill and we are using a timer to show the time elapsed. We use setTimeOut to manage the timer. We log this timer in the console for monitoring.
(function (Drupal, once) {
let counter = 0;
Drupal.behaviors.exampleBehaviour4 = {
attach: (context, settings) => {
once("timer-initalized", ".contact-timer", context).forEach((ele) => {
const timer = context.querySelector(".contact-timer-sec");
timer.textContent = counter;
// Set the timer for user to see the time elapsed
setInterval(() => {
console.log("This is logging");
const timer = document.querySelector(".contact-timer-sec");
timer.textContent = ++counter;
}, 1000);
});
},
};
})(Drupal, once);
On form submission, the timer on DOM gets removed but the console starts throwing an error. This is because the element on which the setTimeOut is acting has been removed from DOM:
To avoid this we can use the detach method like this:
(function (Drupal, once) {
let counter = 0;
let intervalStopper;
Drupal.behaviors.exampleBehaviour4 = {
attach: (context, settings) => {
// Set the timer for user to see the time elapsed
once("timer-initialized", ".contact-timer", context).forEach((ele) => {
const timer = context.querySelector(".contact-timer-sec");
timer.textContent = counter;
intervalStopper = setInterval(() => {
const timer = document.querySelector(".contact-timer-sec");
timer.textContent = ++counter;
console.log("This is logging");
}, 1000);
});
},
// Clear the timer on confirmation
detach: (context, settings, trigger) => {
const timer = context.querySelector(".contact-timer-sec");
if (trigger == "unload" && timer) {
clearInterval(intervalStopper);
}
},
};
})(Drupal, once);
This removes the timer on unload and as seen from the logger, the error does not occur.
We have been using IIFE to write our Drupal code. The initial opening parentheses define an anonymous function which helps prevent the function's scope from polluting the global scope of the entire application. You can pass arguments to your anonymous function by including them as arguments at the end of the function definition.
This also helps us to namespace the parameters however we want them to be used.
Example:
// Function name crisis!!!!
// The function is vulnearble to
// be replaced by some other function
function someFunction() {
// Some code for this function
}
(function (Drupal) {
// Function name crisis averted!
function someFunction() {
// Some code for this other function
}
Drupal.behaviors.exampleBehaviour6 = {
attach: (context, settings) => {
someFunction();
},
};
})(Drupal);
Implementing Drupal behaviors allows for dynamic interactivity, streamlined user interaction, improved user feedback, efficient development and overall enhanced user experience of your website. Drupal.behaviors are flexible and modular, in that they can be executed multiple times on a page, can override and extend existing behavior, and can be automatically re-applied to any content loaded through Ajax.
Looking for a Drupal development agency to help you build interactive web experiences, making the best out of Drupal? We’d love to talk!
Author: Sagar Chauhan
Meet Sagar Chauhan, Lead Engineer, Acquia-certified Frontend Developer, soccer player, and a huge Arsenal fan. Sagar loves long train journeys and checking out latest gadget reviews. If you want to invite him for a meal (and you don’t know how to cook), Maggi would be perfect! :)
Leave us a Comment
A Drupal powered multi-site, multi-lingual platform to enable a unified user experience at SEMI.
Discover how our technology enabled UX Magazine to cater to their massive audience and launch outreach programs.
Discover how a Drupal powered internal portal encouraged the sellers at Flipkart to obtain the latest insights with respect to a particular domain.
Views is a powerful module that allows you to create all sorts of components. It can be used to create something simple such as a list of articles, or complex such as a carousel or even an embedded map.
The Views UI can be intimidating if you’re new to Drupal, but as you use the module, you’ll find bits of functionality hidden deep in the interface.
One feature I want to discuss, which may not be evident at first, is the ability to add Twig code into view a fields.
Adding Twig code into a field allows you to change a field’s output dynamically. Which can be helpful under certain circumstances.
To add Twig code or some HTML into a field, click on the field, expand “Rewrite results”, check “Override the output of this field with custom text” and add your code into the text area.
Today we are talking about Drupal 10, Skills Rot, and Contrib with our hosts.
For show notes visit: www.talkingDrupal.com/385
TopicsNic Laflin - www.nLighteneddevelopment.com @nicxvan John Picozzi - www.epam.com @johnpicozzi Katherine Druckman - katherinedruckman.com @katherined Martin Anderson-Clutz - @mandclu
MOTW CorrespondentMartin Anderson-Clutz - @mandclu Pathauto Automatically generates SEO-friendly URLs (path aliases) for various kinds of content (nodes, taxonomy terms, users) without requiring the user to manually provide one.
Early-bird tickets end February 14, 2023.
MidCamp's pricing is meant to lower the financial barrier to entry for attendees. Every Wednesday/Thursday ticket offers the same experience:
With that said, we know many folks come to camp from different places, and we want to make sure MidCamp is accessible to anyone who wants to join us.
Early Bird ($50) ends February 14, 2023 (with an extension for anyone who submitted a session that is not accepted).
Regular Admission ($100) ends April 5, three weeks before camp, so we can get our catering numbers finalized.
Late/Corporate Admission ($200) is available online until camp starts and then at the door. It’s priced for attendees who have generous professional development budgets and helps makes up for the impact to our catering costs for folks who buy at the last minute.
Students ($25) whether you’re in college, in a bootcamp, or otherwise furthering your education, we want you to join us and learn about the magic that is the Drupal community. We welcome you at this price-point, no questions asked.
Sponsored ($0) tickets are available for those who don’t fit in any of the labels above. MidCamp is committed to being accessible to anyone and everyone who is interested in learning and participating in our community. We’ll teach you, we’ll feed you, and we’ll welcome you with open arms. Get your sponsored ticket here.
As always, Contribution Day is free, but we've split that out as a separate (free) ticket so we can gauge attendance.
Whomever you are, wherever you come from, we look forward to seeing you in March 2023.
That's all a lot to digest, so here's the summary:
Price Ends Early Bird $50 February 14, 2023 Regular $100 April 5, 2023 Corporate/Late $200 at camp! Student $25 at camp! Sponsored $0 at camp!In this second part of a four-part series, Tessa talks about her background, the projects she's worked on, and the vision for her professional future
There is no one way to change a career path. Palantir.net’s four most recent fellows - Paak, Tessa, Travis, and Yang - all joined us through the DrupalEasy program. With their different professional backgrounds and experiences, each offers a unique perspective into what interested them in Drupal and their journey to becoming integral members of Palantir.net.
In each of their written entries they share, among other insights, how they have each adjusted to a fully-remote workplace, how their own skills supported their success as a Fellow, and the importance of Palantir.net’s culture which encourages asking questions, remaining curious, and reaching out for help.
This is Tessa's story.
I’ve always enjoyed learning about tech, mostly focused in hardware; building/maintaining computers, networking, etc. Initially, I didn't really see myself learning programming or coding beyond what was required to make the hardware work; over time, however, I started to figure out that most of the fun with technology was in software, so I began to work in this space. I was working in IT Support before I was fortunate enough to hear about Palantir.net’s Fellowship opportunity to attend DrupalEasy.
My previous experience with networking architecture and command line for computers gave me a bit of a head start with learning Drupal at DrupalEasy, but much of it was new to me. What encouraged me was how Mike Anello, the lead instructor and curriculum developer at DrupalEasy, was so thorough in not only covering the basics, but in encouraging and being available for any and all questions I may have.
Although there is only so much that can be learned about any given subject in the space of only a few months, I was able to take what I learned and build on it in a meaningful way and continue to grow. I felt comfortable in my professional development during my Plantir.net Fellowship, never feeling I was out of my depth or beyond my scope of ability.
As front-end or back-end are the easiest entry points, I opted for back-end and have been working on learning and growing as an engineer. Figuring out how code works is a challenge but quite rewarding once things click into place.
The supportive atmosphere and agile way of thinking and working that Palantir.net provided is unlike anything I’ve experienced before within a work environment. I am glad I received this opportunity and look forward to where it will lead.
An amazing number of Palantiri have contributed to my success and inspired me to grow. I’ve found myself torn in many potential directions of interest and growth that I’m now stuck with the happy challenge of what direction I would like to take in my professional future. Working with tech of any flavor, whether for work or as a hobby, is always an opportunity for learning, and I am glad to see so much potential for my own development and growth.
Having been with Palantir.net for a while now, I’ve found that the entire team has been eager to provide opportunities and support when I’ve shown interest in growing and expanding my current knowledge base. I have already branched out into Dev-Ops and am now looking at some project ownership down the road, as well as more coding in general.
Community Culture Drupal PeopleThe Drupal Association is pleased to announce that it has been selected to host Denaya Dennis, a Fellow from South Sudan in the 2023 Alumni Professional Development Experience (PDE) component of the Mandela Washington Fellowship for Young African Leaders from January 23 to March 3, 2023, sponsored by the U.S. Department of State.
The Mandela Washington Fellowship, the flagship program of the Young African Leaders Initiative (YALI), empowers young African leaders through academic coursework, leadership training, mentoring, networking, professional opportunities, and local community engagement. YALI was created in 2010 and supports young Africans as they spur economic growth and prosperity, strengthen democratic governance, and enhance peace and security across Africa. Since 2014, nearly 5,800 young leaders from every country in Sub-Saharan Africa have participated in the Mandela Washington Fellowship.
New for 2023, 30 Fellowship Alumni have been competitively selected to take part in the 2023 Alumni PDEs – six-week virtual professional placements with U.S. non-governmental organizations, private companies, and government agencies. PDEs allow Fellows to learn and grow as young professionals while providing enriching opportunities for U.S. organizations to participate in collaborative exchanges.
Denaya Dennis Manoah Nigo is an ICT practitioner and a monitoring and evaluation specialist who founded his own organization, Koneta Hub, that provides programming to young people in digital literacy, incubation, and mentorship. He previously volunteered for four years as a teaching assistant at the University of Juba, with a focus on business-related courses, and hopes to continue working with university students in that capacity as early as next year. During the PDE, he wants to further develop his skills in organizational leadership, fundraising and multicultural engagements. Denaya successfully completed the Mandela Washington Fellowship in 2019, studying Leadership in Business at the University of Notre Dame.
The Drupal Association serves the global Drupal community and is honored to cultivate professional development opportunities in collaboration with Denaya through community engagement strategy, local needs assessments, site-building skills, and high impact networking opportunities.
The Mandela Washington Fellowship is a program of the U.S. Department of State with funding provided by the U.S. Government and administered by IREX. For more information about the Mandela Washington Fellowship, visit mandelawashingtonfellowship.org, follow the Fellowship on Twitter at @WashFellowship, and join the conversation at #MandelaFellows.
Press inquiries should be directed to ECA-Press@state.gov.
In this second part of a four-part series, Tessa talks about her background, the projects she's worked on, and the vision for her professional future
There is no one way to change a career path. Palantir.net’s four most recent fellows - Paak, Tessa, Travis, and Yang - all joined us through the DrupalEasy program. With their different professional backgrounds and experiences, each offers a unique perspective into what interested them in Drupal and their journey to becoming integral members of Palantir.net.
In each of their written entries they share, among other insights, how they have each adjusted to a fully-remote workplace, how their own skills supported their success as a Fellow, and the importance of Palantir.net’s culture which encourages asking questions, remaining curious, and reaching out for help.
This is Tessa's story.
I’ve always enjoyed learning about tech, mostly focused in hardware; building/maintaining computers, networking, etc. Initially, I didn't really see myself learning programming or coding beyond what was required to make the hardware work; over time, however, I started to figure out that most of the fun with technology was in software, so I began to work in this space. I was working in IT Support before I was fortunate enough to hear about Palantir.net’s Fellowship opportunity to attend DrupalEasy.
My previous experience with networking architecture and command line for computers gave me a bit of a head start with learning Drupal at DrupalEasy, but much of it was new to me. What encouraged me was how Mike Anello, the lead instructor and curriculum developer at DrupalEasy, was so thorough in not only covering the basics, but in encouraging and being available for any and all questions I may have.
Although there is only so much that can be learned about any given subject in the space of only a few months, I was able to take what I learned and build on it in a meaningful way and continue to grow. I felt comfortable in my professional development during my Plantir.net Fellowship, never feeling I was out of my depth or beyond my scope of ability.
As front-end or back-end are the easiest entry points, I opted for back-end and have been working on learning and growing as an engineer. Figuring out how code works is a challenge but quite rewarding once things click into place.
The supportive atmosphere and agile way of thinking and working that Palantir.net provided is unlike anything I’ve experienced before within a work environment. I am glad I received this opportunity and look forward to where it will lead.
An amazing number of Palantiri have contributed to my success and inspired me to grow. I’ve found myself torn in many potential directions of interest and growth that I’m now stuck with the happy challenge of what direction I would like to take in my professional future. Working with tech of any flavor, whether for work or as a hobby, is always an opportunity for learning, and I am glad to see so much potential for my own development and growth.
Having been with Palantir.net for a while now, I’ve found that the entire team has been eager to provide opportunities and support when I’ve shown interest in growing and expanding my current knowledge base. I have already branched out into Dev-Ops and am now looking at some project ownership down the road, as well as more coding in general.
Community Culture Drupal People