committed by
GitHub
parent
d8d6d20793
commit
f25e3e69f8
17
client/i18n/locales/italian/links.json
Normal file
17
client/i18n/locales/italian/links.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"help-translate-link-url": "https://contribute.freecodecamp.org/#/how-to-translate-files",
|
||||||
|
"footer": {
|
||||||
|
"about-url": "https://www.freecodecamp.org/news/about/",
|
||||||
|
"shop-url": "https://www.freecodecamp.org/shop/",
|
||||||
|
"support-url": "https://www.freecodecamp.org/news/support/",
|
||||||
|
"sponsors-url": "https://www.freecodecamp.org/news/sponsors/",
|
||||||
|
"honesty-url": "https://www.freecodecamp.org/news/academic-honesty-policy/",
|
||||||
|
"coc-url": "https://www.freecodecamp.org/news/code-of-conduct/",
|
||||||
|
"privacy-url": "https://www.freecodecamp.org/news/privacy-policy/",
|
||||||
|
"tos-url": "https://www.freecodecamp.org/news/terms-of-service/",
|
||||||
|
"copyright-url": "https://www.freecodecamp.org/news/copyright-policy/"
|
||||||
|
},
|
||||||
|
"donate": {
|
||||||
|
"other-ways-url": "https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp"
|
||||||
|
}
|
||||||
|
}
|
32
client/i18n/locales/italian/meta-tags.json
Normal file
32
client/i18n/locales/italian/meta-tags.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"title": "Learn to Code — For Free — Coding Courses for Busy People",
|
||||||
|
"description": "Learn to Code — For Free",
|
||||||
|
"social-description": "Learn to Code — For Free",
|
||||||
|
"keywords": [
|
||||||
|
"python",
|
||||||
|
"javascript",
|
||||||
|
"js",
|
||||||
|
"git",
|
||||||
|
"github",
|
||||||
|
"website",
|
||||||
|
"web",
|
||||||
|
"development",
|
||||||
|
"free",
|
||||||
|
"code",
|
||||||
|
"camp",
|
||||||
|
"course",
|
||||||
|
"courses",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"react",
|
||||||
|
"redux",
|
||||||
|
"api",
|
||||||
|
"front",
|
||||||
|
"back",
|
||||||
|
"end",
|
||||||
|
"learn",
|
||||||
|
"tutorial",
|
||||||
|
"programming"
|
||||||
|
],
|
||||||
|
"youre-unsubscribed": "You have been unsubscribed"
|
||||||
|
}
|
819
client/i18n/locales/italian/motivation.json
Normal file
819
client/i18n/locales/italian/motivation.json
Normal file
@ -0,0 +1,819 @@
|
|||||||
|
{
|
||||||
|
"compliments": [
|
||||||
|
"Over the top!",
|
||||||
|
"Down the rabbit hole we go!",
|
||||||
|
"Bring that rain!",
|
||||||
|
"Target acquired.",
|
||||||
|
"Feel that need for speed!",
|
||||||
|
"You've got guts!",
|
||||||
|
"We have liftoff!",
|
||||||
|
"To infinity and beyond!",
|
||||||
|
"Encore!",
|
||||||
|
"Onward!",
|
||||||
|
"Challenge destroyed!",
|
||||||
|
"It's on like Donkey Kong!",
|
||||||
|
"Power level? It's over 9000!",
|
||||||
|
"Coding spree!",
|
||||||
|
"Code long and prosper.",
|
||||||
|
"The crowd goes wild!",
|
||||||
|
"One for the guinness book!",
|
||||||
|
"Flawless victory!",
|
||||||
|
"Most efficient!",
|
||||||
|
"You've got the touch!",
|
||||||
|
"You're on fire!",
|
||||||
|
"The town is now red!",
|
||||||
|
"To the nines!",
|
||||||
|
"To the Batmobile!",
|
||||||
|
"Pull out all the stops!",
|
||||||
|
"You're a wizard, Harry!",
|
||||||
|
"You're an all star!",
|
||||||
|
"Way to go!",
|
||||||
|
"Outta sight!",
|
||||||
|
"You're crushing it!",
|
||||||
|
"What sorcery is this?",
|
||||||
|
"The world rejoices!",
|
||||||
|
"That's the way it's done!",
|
||||||
|
"You rock!",
|
||||||
|
"Woo-hoo!",
|
||||||
|
"We knew you could do it!",
|
||||||
|
"Hyper Combo Finish!",
|
||||||
|
"Nothing but net!",
|
||||||
|
"Boom-shakalaka!",
|
||||||
|
"You're a shooting star!",
|
||||||
|
"You're unstoppable!",
|
||||||
|
"Way cool!",
|
||||||
|
"Walk on that sunshine!",
|
||||||
|
"Keep on trucking!",
|
||||||
|
"Off the charts!",
|
||||||
|
"There is no spoon!",
|
||||||
|
"Cranked it up to 11!",
|
||||||
|
"Escape velocity reached!",
|
||||||
|
"You make this look easy!",
|
||||||
|
"Passed with flying colors!",
|
||||||
|
"You've got this!",
|
||||||
|
"Happy, happy, joy, joy!",
|
||||||
|
"Tomorrow, the world!",
|
||||||
|
"Your powers combined!",
|
||||||
|
"It's alive. It's alive!",
|
||||||
|
"Sonic Boom!",
|
||||||
|
"Here's looking at you, Code!",
|
||||||
|
"Ride like the wind!",
|
||||||
|
"Legen - wait for it - dary!",
|
||||||
|
"Ludicrous Speed! Go!",
|
||||||
|
"Most triumphant!",
|
||||||
|
"One loop to rule them all!",
|
||||||
|
"By the power of Grayskull!",
|
||||||
|
"You did it!",
|
||||||
|
"Storm that castle!",
|
||||||
|
"Face-melting guitar solo!",
|
||||||
|
"Checkmate!",
|
||||||
|
"Bodacious!",
|
||||||
|
"Tubular!",
|
||||||
|
"You're outta sight!",
|
||||||
|
"Keep calm and code on!",
|
||||||
|
"Even sad panda smiles!",
|
||||||
|
"Even grumpy cat approves!",
|
||||||
|
"Kool Aid Man says oh yeah!",
|
||||||
|
"Bullseye!",
|
||||||
|
"Far out!",
|
||||||
|
"You're heating up!",
|
||||||
|
"Standing ovation!",
|
||||||
|
"Nice one!",
|
||||||
|
"All right!",
|
||||||
|
"Hasta la vista, challenge!",
|
||||||
|
"Terminated.",
|
||||||
|
"Off the hook!",
|
||||||
|
"Thundercats, Hooo!",
|
||||||
|
"Shiver me timbers!",
|
||||||
|
"Raise the roof!",
|
||||||
|
"Bingo!",
|
||||||
|
"Even honeybadger cares!",
|
||||||
|
"Helm, Warp Nine. Engage!",
|
||||||
|
"Gotta code 'em all!",
|
||||||
|
"Spool up the FTL drive!",
|
||||||
|
"Cool beans!",
|
||||||
|
"They're in another castle.",
|
||||||
|
"Power UP!",
|
||||||
|
"Pikachu chooses you!",
|
||||||
|
"I gotta have more cow bell.",
|
||||||
|
"Gotta go fast!",
|
||||||
|
"Yipee!",
|
||||||
|
"Cowabunga!",
|
||||||
|
"Moon Prism Power!",
|
||||||
|
"Plus Ultra!"
|
||||||
|
],
|
||||||
|
"motivationalQuotes": [
|
||||||
|
{
|
||||||
|
"quote": "Whatever you are, be a good one.",
|
||||||
|
"author": "Abraham Lincoln"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A change in perspective is worth 80 IQ points.",
|
||||||
|
"author": "Alan Kay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The best way to predict the future is to invent it.",
|
||||||
|
"author": "Alan Kay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The future is not laid out on a track. It is something that we can decide, and to the extent that we do not violate any known laws of the universe, we can probably make it work the way that we want to.",
|
||||||
|
"author": "Alan Kay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We can only see a short distance ahead, but we can see plenty there that needs to be done.",
|
||||||
|
"author": "Alan Turing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "In the depth of winter, I finally learned that within me there lay an invincible summer.",
|
||||||
|
"author": "Albert Camus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A person who never made a mistake never tried anything new.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Creativity is intelligence having fun.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I have no special talents. I am only passionately curious.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Life is like riding a bicycle. To keep your balance, you must keep moving.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Make everything as simple as possible, but not simpler.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Never memorize something that you can look up.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Once we accept our limits, we go beyond them.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Play is the highest form of research.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We cannot solve our problems with the same thinking we used when we created them.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Wisdom is not a product of schooling but of the lifelong attempt to acquire it.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Your imagination is your preview of life's coming attractions.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is only one corner of the universe you can be certain of improving, and that's your own self.",
|
||||||
|
"author": "Aldous Huxley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The most common way people give up their power is by thinking they don't have any.",
|
||||||
|
"author": "Alice Walker"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Follow your inner moonlight. Don't hide the madness.",
|
||||||
|
"author": "Allen Ginsberg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The most difficult thing is the decision to act. The rest is merely tenacity.",
|
||||||
|
"author": "Amelia Earhart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Life shrinks or expands in proportion with one's courage.",
|
||||||
|
"author": "Anaïs Nin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Weeks of programming can save you hours of planning.",
|
||||||
|
"author": "Unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Quality is not an act, it is a habit.",
|
||||||
|
"author": "Aristotle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Start where you are. Use what you have. Do what you can.",
|
||||||
|
"author": "Arthur Ashe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Nothing is impossible, the word itself says \"I'm possible\"!",
|
||||||
|
"author": "Audrey Hepburn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Every strike brings me closer to the next home run.",
|
||||||
|
"author": "Babe Ruth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "By failing to prepare, you are preparing to fail.",
|
||||||
|
"author": "Benjamin Franklin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Tell me and I forget. Teach me and I remember. Involve me and I learn.",
|
||||||
|
"author": "Benjamin Franklin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Well done is better than well said.",
|
||||||
|
"author": "Benjamin Franklin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There are no short cuts to any place worth going.",
|
||||||
|
"author": "Beverly Sills"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Controlling complexity is the essence of computer programming.",
|
||||||
|
"author": "Brian Kernighan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I fear not the man who has practiced 10,000 kicks once, but I fear the man who has practiced one kick 10,000 times.",
|
||||||
|
"author": "Bruce Lee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There are far, far better things ahead than any we leave behind.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We are what we believe we are.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "With the possible exception of the equator, everything begins somewhere.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You are never too old to set another goal, or to dream a new dream.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Somewhere, something incredible is waiting to be known.",
|
||||||
|
"author": "Carl Sagan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you're not making mistakes, then you're not making decisions.",
|
||||||
|
"author": "Catherine Cook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Find what you love and let it kill you.",
|
||||||
|
"author": "Charles Bukowski"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "What matters most is how well you walk through the fire.",
|
||||||
|
"author": "Charles Bukowski"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is not the strongest of the species that survive, nor the most intelligent, but the one most responsive to change.",
|
||||||
|
"author": "Charles Darwin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Life is 10% what happens to you and 90% how you react to it.",
|
||||||
|
"author": "Charles R. Swindoll"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You will do foolish things, but do them with enthusiasm.",
|
||||||
|
"author": "Colette"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It does not matter how slowly you go as long as you do not stop.",
|
||||||
|
"author": "Confucius"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Real knowledge is to know the extent of one's ignorance.",
|
||||||
|
"author": "Confucius"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The past cannot be changed. The future is yet in your power.",
|
||||||
|
"author": "Confucius"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Looking at code you wrote more than two weeks ago is like looking at code you are seeing for the first time.",
|
||||||
|
"author": "Dan Hurvitz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Someday is not a day of the week.",
|
||||||
|
"author": "Denise Brennan-Nelson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "UNIX is simple. It just takes a genius to understand its simplicity.",
|
||||||
|
"author": "Dennis Ritchie"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Computers are good at following instructions, but not at reading your mind.",
|
||||||
|
"author": "Donald Knuth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A good programmer is someone who always looks both ways before crossing a one-way street.",
|
||||||
|
"author": "Doug Linder"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Tough times never last, but tough people do.",
|
||||||
|
"author": "Dr. Robert Schuller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If things start happening, don't worry, don't stew, just go right along and you'll start happening too.",
|
||||||
|
"author": "Dr. Seuss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do not go gentle into that good night. Rage, rage against the dying of the light.",
|
||||||
|
"author": "Dylan Thomas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The question of whether computers can think is like the question of whether submarines can swim.",
|
||||||
|
"author": "E.W. Dijkstra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Any code of your own that you haven't looked at for six or more months might as well have been written by someone else.",
|
||||||
|
"author": "Eagleson's Law"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do one thing every day that scares you.",
|
||||||
|
"author": "Eleanor Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "With the new day comes new strength and new thoughts.",
|
||||||
|
"author": "Eleanor Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You must do the things you think you cannot do.",
|
||||||
|
"author": "Eleanor Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Light tomorrow with today.",
|
||||||
|
"author": "Elizabeth Barrett Browning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Forever is composed of nows.",
|
||||||
|
"author": "Emily Dickinson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter.",
|
||||||
|
"author": "Eric Raymond"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you don't risk anything, you risk even more.",
|
||||||
|
"author": "Erica Jong"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The world breaks everyone, and afterward, many are strong at the broken places.",
|
||||||
|
"author": "Ernest Hemingway"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is nothing noble in being superior to your fellow man; true nobility is being superior to your former self.",
|
||||||
|
"author": "Ernest Hemingway"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Never confuse a single defeat with a final defeat.",
|
||||||
|
"author": "F. Scott Fitzgerald"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I attribute my success to this - I never gave or took any excuse.",
|
||||||
|
"author": "Florence Nightingale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The best revenge is massive success.",
|
||||||
|
"author": "Frank Sinatra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The only limit to our realization of tomorrow, will be our doubts of today.",
|
||||||
|
"author": "Franklin D. Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Right or wrong, it's very pleasant to break something from time to time.",
|
||||||
|
"author": "Fyodor Dostoevsky"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The harder I work, the luckier I get.",
|
||||||
|
"author": "Gary Player"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Giving up is the only sure way to fail.",
|
||||||
|
"author": "Gena Showalter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards.",
|
||||||
|
"author": "Gene Spafford"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing.",
|
||||||
|
"author": "George Bernard Shaw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.",
|
||||||
|
"author": "George Carrette"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Discovering the unexpected is more important than confirming the known.",
|
||||||
|
"author": "George Box"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We only see what we know.",
|
||||||
|
"author": "Goethe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Without hard work, nothing grows but weeds.",
|
||||||
|
"author": "Gordon B. Hinckley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The function of good software is to make the complex appear to be simple.",
|
||||||
|
"author": "Grady Booch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "When you know that you're capable of dealing with whatever comes, you have the only security the world has to offer.",
|
||||||
|
"author": "Harry Browne"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Pain is inevitable. Suffering is optional.",
|
||||||
|
"author": "Haruki Murakami"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence.",
|
||||||
|
"author": "Helen Keller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The price of anything is the amount of life you exchange for it.",
|
||||||
|
"author": "Henry David Thoreau"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Whether you think you can or think you can't, you're right.",
|
||||||
|
"author": "Henry Ford"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The most exciting phrase to hear in science, the one that heralds discoveries, is not 'Eureka!' but 'Now that's funny…'",
|
||||||
|
"author": "Isaac Asimov"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We are all failures. At least the best of us are.",
|
||||||
|
"author": "J.M. Barrie"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can't wait for inspiration. You have to go after it with a club.",
|
||||||
|
"author": "Jack London"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't wish it were easier, wish you were better.",
|
||||||
|
"author": "Jim Rohn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "By seeking and blundering we learn.",
|
||||||
|
"author": "Johann Wolfgang von Goethe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Knowing is not enough; we must apply. Wishing is not enough; we must do.",
|
||||||
|
"author": "Johann Wolfgang von Goethe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We first make our habits, then our habits make us.",
|
||||||
|
"author": "John Dryden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The power of imagination makes us infinite.",
|
||||||
|
"author": "John Muir"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "May you live every day of your life.",
|
||||||
|
"author": "Jonathan Swift"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Perseverance is failing 19 times and succeeding the 20th.",
|
||||||
|
"author": "Julie Andrews"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The work of today is the history of tomorrow, and we are its makers.",
|
||||||
|
"author": "Juliette Gordon Low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you reveal your secrets to the wind, you should not blame the wind for revealing them to the trees.",
|
||||||
|
"author": "Kahlil Gibran"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Optimism is an occupational hazard of programming; feedback is the treatment.",
|
||||||
|
"author": "Kent Beck"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Opportunity does not knock, it presents itself when you beat down the door.",
|
||||||
|
"author": "Kyle Chandler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "To iterate is human, to recurse divine.",
|
||||||
|
"author": "Peter Deutsch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A good traveler has no fixed plans and is not intent on arriving.",
|
||||||
|
"author": "Lao Tzu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "An ant on the move does more than a dozing ox.",
|
||||||
|
"author": "Lao Tzu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step.",
|
||||||
|
"author": "Lao Tzu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "That's the thing about people who think they hate computers. What they really hate is lousy programmers.",
|
||||||
|
"author": "Larry Niven"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It had long since come to my attention that people of accomplishment rarely sat back and let things happen to them. They went out and happened to things.",
|
||||||
|
"author": "Leonardo da Vinci"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you're any good at all, you know you can be better.",
|
||||||
|
"author": "Lindsay Buckingham"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If people never did silly things, nothing intelligent would ever get done.",
|
||||||
|
"author": "Ludwig Wittgenstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You only live once, but if you do it right, once is enough.",
|
||||||
|
"author": "Mae West"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Live as if you were to die tomorrow. Learn as if you were to live forever.",
|
||||||
|
"author": "Mahatma Gandhi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Strength does not come from physical capacity. It comes from an indomitable will.",
|
||||||
|
"author": "Mahatma Gandhi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "One person's 'paranoia' is another person's 'engineering redundancy'.",
|
||||||
|
"author": "Marcus J. Ranum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less.",
|
||||||
|
"author": "Marie Curie"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you have everything under control, you're not moving fast enough.",
|
||||||
|
"author": "Mario Andretti"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Education: the path from cocky ignorance to miserable uncertainty.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It ain't what you don't know that gets you into trouble. It's what you know for sure that just ain't so.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The secret of getting ahead is getting started.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The two most important days in your life are the day you are born and the day you find out why.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
|
||||||
|
"author": "Martin Fowler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I know, somehow, that only when it is dark enough can you see the stars.",
|
||||||
|
"author": "Martin Luther King Jr."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is never too late to be what you might have been.",
|
||||||
|
"author": "Mary Anne Evans"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Nothing will work unless you do.",
|
||||||
|
"author": "Maya Angelou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty.",
|
||||||
|
"author": "Maya Angelou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We may encounter many defeats, but we must not be defeated.",
|
||||||
|
"author": "Maya Angelou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Everybody has talent, but ability takes hard work.",
|
||||||
|
"author": "Michael Jordan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I've missed more than 9,000 shots during my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed.",
|
||||||
|
"author": "Michael Jordan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Impossible is just a big word thrown around by small men who find it easier to live in the world they've been given than to explore the power they have to change it. Impossible is not a fact. It's an opinion. Impossible is not a declaration. It's a dare. Impossible is potential. Impossible is temporary. Impossible is nothing.",
|
||||||
|
"author": "Muhammad Ali"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A winner is a dreamer who never gives up.",
|
||||||
|
"author": "Nelson Mandela"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It always seems impossible until it's done.",
|
||||||
|
"author": "Nelson Mandela"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Failure will never overtake me if my determination to succeed is strong enough.",
|
||||||
|
"author": "Og Mandino"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I am not young enough to know everything.",
|
||||||
|
"author": "Oscar Wilde"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is only one thing that makes a dream impossible to achieve: the fear of failure.",
|
||||||
|
"author": "Paulo Coelho"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Never go to bed mad. Stay up and fight.",
|
||||||
|
"author": "Phyllis Diller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can't cross the sea merely by standing and staring at the water.",
|
||||||
|
"author": "Rabindranath Tagore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The only person you are destined to become is the person you decide to be.",
|
||||||
|
"author": "Ralph Waldo Emerson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "What you do speaks so loudly that I cannot hear what you say.",
|
||||||
|
"author": "Ralph Waldo Emerson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "People who are crazy enough to think they can change the world, are the ones who do.",
|
||||||
|
"author": "Rob Siltanen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The best way out is always through.",
|
||||||
|
"author": "Robert Frost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Today's accomplishments were yesterday's impossibilities.",
|
||||||
|
"author": "Robert H. Schuller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't be satisfied with stories, how things have gone with others. Unfold your own myth.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Forget safety. Live where you fear to live. Destroy your reputation. Be notorious.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Sell your cleverness and buy bewilderment.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The cure for pain is in the pain.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Have no fear of perfection - you'll never reach it.",
|
||||||
|
"author": "Salvador Dalí"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't watch the clock. Do what it does. Keep going.",
|
||||||
|
"author": "Sam Levenson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Ever Tried. Ever failed. No matter. Try again. Fail again. Fail better.",
|
||||||
|
"author": "Samuel Beckett"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The more you know, the more you realize you know nothing.",
|
||||||
|
"author": "Socrates"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.",
|
||||||
|
"author": "Stephen Hawking"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The universe doesn't allow perfection.",
|
||||||
|
"author": "Stephen Hawking"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Whether you want to uncover the secrets of the universe, or you want to pursue a career in the 21st century, basic computer programming is an essential skill to learn.",
|
||||||
|
"author": "Stephen Hawking"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The scariest moment is always just before you start.",
|
||||||
|
"author": "Stephen King"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can, you should, and if you're brave enough to start, you will.",
|
||||||
|
"author": "Stephen King"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Arise, Awake and Stop not until the goal is reached.",
|
||||||
|
"author": "Swami Vivekananda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is said that your life flashes before your eyes just before you die. That is true, it's called Life.",
|
||||||
|
"author": "Terry Pratchett"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Believe you can and you're halfway there.",
|
||||||
|
"author": "Theodore Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I have not failed. I've just found 10,000 ways that won't work.",
|
||||||
|
"author": "Thomas A. Edison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.",
|
||||||
|
"author": "Thomas A. Edison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The harder the conflict, the more glorious the triumph.",
|
||||||
|
"author": "Thomas Paine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The Web as I envisaged it, we have not seen it yet. The future is still so much bigger than the past.",
|
||||||
|
"author": "Tim Berners-Lee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Failure is the condiment that gives success its flavor.",
|
||||||
|
"author": "Truman Capote"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Those who says it cannot be done should not interrupt the person doing it.",
|
||||||
|
"author": "Unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Even if you fall on your face, you're still moving forward.",
|
||||||
|
"author": "Victor Kiam"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It's not whether you get knocked down, it's whether you get up.",
|
||||||
|
"author": "Vince Lombardi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I dream my painting and I paint my dream.",
|
||||||
|
"author": "Vincent van Gogh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Let us cultivate our garden.",
|
||||||
|
"author": "Voltaire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Aim for the moon. If you miss, you may hit a star.",
|
||||||
|
"author": "W. Clement Stone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The way to get started is to quit talking and begin doing.",
|
||||||
|
"author": "Walt Disney"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You miss 100% of the shots you don't take.",
|
||||||
|
"author": "Wayne Gretzky"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't let yesterday take up too much of today.",
|
||||||
|
"author": "Will Rogers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Even if you're on the right track, you'll get run over if you just sit there.",
|
||||||
|
"author": "Will Rogers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do not wait to strike till the iron is hot; but make it hot by striking.",
|
||||||
|
"author": "William Butler Yeats"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You cannot swim for new horizons until you have courage to lose sight of the shore.",
|
||||||
|
"author": "William Faulkner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Be not afraid of greatness. Some are born great, some achieve greatness, and others have greatness thrust upon them.",
|
||||||
|
"author": "William Shakespeare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We know what we are, but not what we may be.",
|
||||||
|
"author": "William Shakespeare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "In theory there is no difference between theory and practice. In practice there is.",
|
||||||
|
"author": "Yogi Berra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can see a lot by just looking.",
|
||||||
|
"author": "Yogi Berra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is no elevator to success, you have to take the stairs.",
|
||||||
|
"author": "Zig Ziglar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You don't have to be great to start, but you have to start to be great.",
|
||||||
|
"author": "Zig Ziglar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
62
client/i18n/locales/italian/trending.json
Normal file
62
client/i18n/locales/italian/trending.json
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"article0title":"10 to the Power of 0",
|
||||||
|
"article0link":"https://www.freecodecamp.org/news/10-to-the-power-of-0-the-zero-exponent-rule-and-the-power-of-zero-explained/",
|
||||||
|
"article1title":"Git Reset to Remote",
|
||||||
|
"article1link":"https://www.freecodecamp.org/news/git-reset-to-remote-head-how-to-reset-a-remote-branch-to-origin/",
|
||||||
|
"article2title":"R Value in Statistics",
|
||||||
|
"article2link":"https://www.freecodecamp.org/news/what-is-a-correlation-coefficient-r-value-in-statistics-explains/",
|
||||||
|
"article3title":"What is Economics?",
|
||||||
|
"article3link":"https://www.freecodecamp.org/news/what-is-economics/",
|
||||||
|
"article4title":"Module Exports",
|
||||||
|
"article4link":"https://www.freecodecamp.org/news/node-module-exports-explained-with-javascript-export-function-examples/",
|
||||||
|
"article5title":"Python VS JavaScript",
|
||||||
|
"article5link":"https://www.freecodecamp.org/news/python-vs-javascript-what-are-the-key-differences-between-the-two-popular-programming-languages/",
|
||||||
|
"article6title":"Model View Controller",
|
||||||
|
"article6link":"https://www.freecodecamp.org/news/model-view-architecture/",
|
||||||
|
"article7title":"React Testing Library",
|
||||||
|
"article7link":"https://www.freecodecamp.org/news/react-testing-library-tutorial-javascript-example-code/",
|
||||||
|
"article8title":"ASCII Table Chart",
|
||||||
|
"article8link":"https://www.freecodecamp.org/news/ascii-table-hex-to-ascii-value-character-code-chart-2/",
|
||||||
|
"article9title":"Data Validation",
|
||||||
|
"article9link":"https://www.freecodecamp.org/news/form-validation-with-html5-and-javascript/",
|
||||||
|
"article10title":"Recursion",
|
||||||
|
"article10link":"https://www.freecodecamp.org/news/what-is-recursion-in-javascript/",
|
||||||
|
"article11title":"ISO File",
|
||||||
|
"article11link":"https://www.freecodecamp.org/news/what-is-an-iso-file-explained-in-plain-english/",
|
||||||
|
"article12title":"ADB",
|
||||||
|
"article12link":"https://www.freecodecamp.org/news/adb-android-install-guide-drivers-and-commands/",
|
||||||
|
"article13title":"MBR VS GPT",
|
||||||
|
"article13link":"https://www.freecodecamp.org/news/mbr-vs-gpt-whats-the-difference-between-an-mbr-partition-and-a-gpt-partition-solved/",
|
||||||
|
"article14title":"Debounce",
|
||||||
|
"article14link":"https://www.freecodecamp.org/news/javascript-debounce-example/",
|
||||||
|
"article15title":"Helm Chart",
|
||||||
|
"article15link":"https://www.freecodecamp.org/news/what-is-a-helm-chart-tutorial-for-kubernetes-beginners/",
|
||||||
|
"article16title":"80-20 Rule",
|
||||||
|
"article16link":"https://www.freecodecamp.org/news/the-80-20-rule-pareto-principle-explained-in-plain-english/",
|
||||||
|
"article17title":"OSI Model",
|
||||||
|
"article17link":"https://www.freecodecamp.org/news/osi-model-networking-layers-explained-in-plain-english/",
|
||||||
|
"article18title":"HTML Link Code",
|
||||||
|
"article18link":"https://www.freecodecamp.org/news/html-link-code-how-to-insert-a-link-to-a-website-with-href-3/",
|
||||||
|
"article19title":"SDLC",
|
||||||
|
"article19link":"https://www.freecodecamp.org/news/what-is-sdlc-software-development-life-cycle-phases-methodologies-and-processes-explained/",
|
||||||
|
"article20title":"Inductive VS Deductive",
|
||||||
|
"article20link":"https://www.freecodecamp.org/news/inductive-vs-deductive-reasoning/",
|
||||||
|
"article21title":"JavaScript Empty Array",
|
||||||
|
"article21link":"https://www.freecodecamp.org/news/check-if-javascript-array-is-empty-or-not-with-length/",
|
||||||
|
"article22title":"Best Instagram Post Time",
|
||||||
|
"article22link":"https://www.freecodecamp.org/news/the-best-time-to-post-on-instagram-the-best-days-and-times-to-reach-your-ig-followers/",
|
||||||
|
"article23title":"Garbage Collection in Java",
|
||||||
|
"article23link":"https://www.freecodecamp.org/news/garbage-collection-in-java-what-is-gc-and-how-it-works-in-the-jvm/",
|
||||||
|
"article24title":"Auto-Numbering in Excel",
|
||||||
|
"article24link":"https://www.freecodecamp.org/news/auto-numbering-in-excel/",
|
||||||
|
"article25title":"JavaScript Keycode List",
|
||||||
|
"article25link":"https://www.freecodecamp.org/news/javascript-keycode-list-keypress-event-key-codes/",
|
||||||
|
"article26title":"JavaScript Reverse Array",
|
||||||
|
"article26link":"https://www.freecodecamp.org/news/javascript-array-reverse-tutorial-with-example-js-code/",
|
||||||
|
"article27title":"How to Screenshot on Mac",
|
||||||
|
"article27link":"https://www.freecodecamp.org/news/how-to-take-a-screenshot-on-a-mac-keyboard-shortcut/",
|
||||||
|
"article28title":"How to Reverse Image Search",
|
||||||
|
"article28link":"https://www.freecodecamp.org/news/how-to-reverse-image-search-on-your-phone-or-desktop/",
|
||||||
|
"article29title":"Ternary Operator JavaScript",
|
||||||
|
"article29link":"https://www.freecodecamp.org/news/ternary-operator-javascript-if-statement-tutorial/"
|
||||||
|
}
|
17
client/i18n/locales/portuguese/links.json
Normal file
17
client/i18n/locales/portuguese/links.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"help-translate-link-url": "https://contribute.freecodecamp.org/#/how-to-translate-files",
|
||||||
|
"footer": {
|
||||||
|
"about-url": "https://www.freecodecamp.org/news/about/",
|
||||||
|
"shop-url": "https://www.freecodecamp.org/shop/",
|
||||||
|
"support-url": "https://www.freecodecamp.org/news/support/",
|
||||||
|
"sponsors-url": "https://www.freecodecamp.org/news/sponsors/",
|
||||||
|
"honesty-url": "https://www.freecodecamp.org/news/academic-honesty-policy/",
|
||||||
|
"coc-url": "https://www.freecodecamp.org/news/code-of-conduct/",
|
||||||
|
"privacy-url": "https://www.freecodecamp.org/news/privacy-policy/",
|
||||||
|
"tos-url": "https://www.freecodecamp.org/news/terms-of-service/",
|
||||||
|
"copyright-url": "https://www.freecodecamp.org/news/copyright-policy/"
|
||||||
|
},
|
||||||
|
"donate": {
|
||||||
|
"other-ways-url": "https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp"
|
||||||
|
}
|
||||||
|
}
|
32
client/i18n/locales/portuguese/meta-tags.json
Normal file
32
client/i18n/locales/portuguese/meta-tags.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"title": "Learn to Code — For Free — Coding Courses for Busy People",
|
||||||
|
"description": "Learn to Code — For Free",
|
||||||
|
"social-description": "Learn to Code — For Free",
|
||||||
|
"keywords": [
|
||||||
|
"python",
|
||||||
|
"javascript",
|
||||||
|
"js",
|
||||||
|
"git",
|
||||||
|
"github",
|
||||||
|
"website",
|
||||||
|
"web",
|
||||||
|
"development",
|
||||||
|
"free",
|
||||||
|
"code",
|
||||||
|
"camp",
|
||||||
|
"course",
|
||||||
|
"courses",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"react",
|
||||||
|
"redux",
|
||||||
|
"api",
|
||||||
|
"front",
|
||||||
|
"back",
|
||||||
|
"end",
|
||||||
|
"learn",
|
||||||
|
"tutorial",
|
||||||
|
"programming"
|
||||||
|
],
|
||||||
|
"youre-unsubscribed": "You have been unsubscribed"
|
||||||
|
}
|
819
client/i18n/locales/portuguese/motivation.json
Normal file
819
client/i18n/locales/portuguese/motivation.json
Normal file
@ -0,0 +1,819 @@
|
|||||||
|
{
|
||||||
|
"compliments": [
|
||||||
|
"Over the top!",
|
||||||
|
"Down the rabbit hole we go!",
|
||||||
|
"Bring that rain!",
|
||||||
|
"Target acquired.",
|
||||||
|
"Feel that need for speed!",
|
||||||
|
"You've got guts!",
|
||||||
|
"We have liftoff!",
|
||||||
|
"To infinity and beyond!",
|
||||||
|
"Encore!",
|
||||||
|
"Onward!",
|
||||||
|
"Challenge destroyed!",
|
||||||
|
"It's on like Donkey Kong!",
|
||||||
|
"Power level? It's over 9000!",
|
||||||
|
"Coding spree!",
|
||||||
|
"Code long and prosper.",
|
||||||
|
"The crowd goes wild!",
|
||||||
|
"One for the guinness book!",
|
||||||
|
"Flawless victory!",
|
||||||
|
"Most efficient!",
|
||||||
|
"You've got the touch!",
|
||||||
|
"You're on fire!",
|
||||||
|
"The town is now red!",
|
||||||
|
"To the nines!",
|
||||||
|
"To the Batmobile!",
|
||||||
|
"Pull out all the stops!",
|
||||||
|
"You're a wizard, Harry!",
|
||||||
|
"You're an all star!",
|
||||||
|
"Way to go!",
|
||||||
|
"Outta sight!",
|
||||||
|
"You're crushing it!",
|
||||||
|
"What sorcery is this?",
|
||||||
|
"The world rejoices!",
|
||||||
|
"That's the way it's done!",
|
||||||
|
"You rock!",
|
||||||
|
"Woo-hoo!",
|
||||||
|
"We knew you could do it!",
|
||||||
|
"Hyper Combo Finish!",
|
||||||
|
"Nothing but net!",
|
||||||
|
"Boom-shakalaka!",
|
||||||
|
"You're a shooting star!",
|
||||||
|
"You're unstoppable!",
|
||||||
|
"Way cool!",
|
||||||
|
"Walk on that sunshine!",
|
||||||
|
"Keep on trucking!",
|
||||||
|
"Off the charts!",
|
||||||
|
"There is no spoon!",
|
||||||
|
"Cranked it up to 11!",
|
||||||
|
"Escape velocity reached!",
|
||||||
|
"You make this look easy!",
|
||||||
|
"Passed with flying colors!",
|
||||||
|
"You've got this!",
|
||||||
|
"Happy, happy, joy, joy!",
|
||||||
|
"Tomorrow, the world!",
|
||||||
|
"Your powers combined!",
|
||||||
|
"It's alive. It's alive!",
|
||||||
|
"Sonic Boom!",
|
||||||
|
"Here's looking at you, Code!",
|
||||||
|
"Ride like the wind!",
|
||||||
|
"Legen - wait for it - dary!",
|
||||||
|
"Ludicrous Speed! Go!",
|
||||||
|
"Most triumphant!",
|
||||||
|
"One loop to rule them all!",
|
||||||
|
"By the power of Grayskull!",
|
||||||
|
"You did it!",
|
||||||
|
"Storm that castle!",
|
||||||
|
"Face-melting guitar solo!",
|
||||||
|
"Checkmate!",
|
||||||
|
"Bodacious!",
|
||||||
|
"Tubular!",
|
||||||
|
"You're outta sight!",
|
||||||
|
"Keep calm and code on!",
|
||||||
|
"Even sad panda smiles!",
|
||||||
|
"Even grumpy cat approves!",
|
||||||
|
"Kool Aid Man says oh yeah!",
|
||||||
|
"Bullseye!",
|
||||||
|
"Far out!",
|
||||||
|
"You're heating up!",
|
||||||
|
"Standing ovation!",
|
||||||
|
"Nice one!",
|
||||||
|
"All right!",
|
||||||
|
"Hasta la vista, challenge!",
|
||||||
|
"Terminated.",
|
||||||
|
"Off the hook!",
|
||||||
|
"Thundercats, Hooo!",
|
||||||
|
"Shiver me timbers!",
|
||||||
|
"Raise the roof!",
|
||||||
|
"Bingo!",
|
||||||
|
"Even honeybadger cares!",
|
||||||
|
"Helm, Warp Nine. Engage!",
|
||||||
|
"Gotta code 'em all!",
|
||||||
|
"Spool up the FTL drive!",
|
||||||
|
"Cool beans!",
|
||||||
|
"They're in another castle.",
|
||||||
|
"Power UP!",
|
||||||
|
"Pikachu chooses you!",
|
||||||
|
"I gotta have more cow bell.",
|
||||||
|
"Gotta go fast!",
|
||||||
|
"Yipee!",
|
||||||
|
"Cowabunga!",
|
||||||
|
"Moon Prism Power!",
|
||||||
|
"Plus Ultra!"
|
||||||
|
],
|
||||||
|
"motivationalQuotes": [
|
||||||
|
{
|
||||||
|
"quote": "Whatever you are, be a good one.",
|
||||||
|
"author": "Abraham Lincoln"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A change in perspective is worth 80 IQ points.",
|
||||||
|
"author": "Alan Kay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The best way to predict the future is to invent it.",
|
||||||
|
"author": "Alan Kay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The future is not laid out on a track. It is something that we can decide, and to the extent that we do not violate any known laws of the universe, we can probably make it work the way that we want to.",
|
||||||
|
"author": "Alan Kay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We can only see a short distance ahead, but we can see plenty there that needs to be done.",
|
||||||
|
"author": "Alan Turing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "In the depth of winter, I finally learned that within me there lay an invincible summer.",
|
||||||
|
"author": "Albert Camus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A person who never made a mistake never tried anything new.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Creativity is intelligence having fun.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I have no special talents. I am only passionately curious.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Life is like riding a bicycle. To keep your balance, you must keep moving.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Make everything as simple as possible, but not simpler.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Never memorize something that you can look up.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Once we accept our limits, we go beyond them.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Play is the highest form of research.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We cannot solve our problems with the same thinking we used when we created them.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Wisdom is not a product of schooling but of the lifelong attempt to acquire it.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Your imagination is your preview of life's coming attractions.",
|
||||||
|
"author": "Albert Einstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is only one corner of the universe you can be certain of improving, and that's your own self.",
|
||||||
|
"author": "Aldous Huxley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The most common way people give up their power is by thinking they don't have any.",
|
||||||
|
"author": "Alice Walker"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Follow your inner moonlight. Don't hide the madness.",
|
||||||
|
"author": "Allen Ginsberg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The most difficult thing is the decision to act. The rest is merely tenacity.",
|
||||||
|
"author": "Amelia Earhart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Life shrinks or expands in proportion with one's courage.",
|
||||||
|
"author": "Anaïs Nin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Weeks of programming can save you hours of planning.",
|
||||||
|
"author": "Unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Quality is not an act, it is a habit.",
|
||||||
|
"author": "Aristotle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Start where you are. Use what you have. Do what you can.",
|
||||||
|
"author": "Arthur Ashe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Nothing is impossible, the word itself says \"I'm possible\"!",
|
||||||
|
"author": "Audrey Hepburn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Every strike brings me closer to the next home run.",
|
||||||
|
"author": "Babe Ruth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "By failing to prepare, you are preparing to fail.",
|
||||||
|
"author": "Benjamin Franklin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Tell me and I forget. Teach me and I remember. Involve me and I learn.",
|
||||||
|
"author": "Benjamin Franklin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Well done is better than well said.",
|
||||||
|
"author": "Benjamin Franklin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There are no short cuts to any place worth going.",
|
||||||
|
"author": "Beverly Sills"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Controlling complexity is the essence of computer programming.",
|
||||||
|
"author": "Brian Kernighan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I fear not the man who has practiced 10,000 kicks once, but I fear the man who has practiced one kick 10,000 times.",
|
||||||
|
"author": "Bruce Lee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There are far, far better things ahead than any we leave behind.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We are what we believe we are.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "With the possible exception of the equator, everything begins somewhere.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You are never too old to set another goal, or to dream a new dream.",
|
||||||
|
"author": "C.S. Lewis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Somewhere, something incredible is waiting to be known.",
|
||||||
|
"author": "Carl Sagan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you're not making mistakes, then you're not making decisions.",
|
||||||
|
"author": "Catherine Cook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Find what you love and let it kill you.",
|
||||||
|
"author": "Charles Bukowski"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "What matters most is how well you walk through the fire.",
|
||||||
|
"author": "Charles Bukowski"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is not the strongest of the species that survive, nor the most intelligent, but the one most responsive to change.",
|
||||||
|
"author": "Charles Darwin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Life is 10% what happens to you and 90% how you react to it.",
|
||||||
|
"author": "Charles R. Swindoll"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You will do foolish things, but do them with enthusiasm.",
|
||||||
|
"author": "Colette"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It does not matter how slowly you go as long as you do not stop.",
|
||||||
|
"author": "Confucius"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Real knowledge is to know the extent of one's ignorance.",
|
||||||
|
"author": "Confucius"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The past cannot be changed. The future is yet in your power.",
|
||||||
|
"author": "Confucius"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Looking at code you wrote more than two weeks ago is like looking at code you are seeing for the first time.",
|
||||||
|
"author": "Dan Hurvitz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Someday is not a day of the week.",
|
||||||
|
"author": "Denise Brennan-Nelson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "UNIX is simple. It just takes a genius to understand its simplicity.",
|
||||||
|
"author": "Dennis Ritchie"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Computers are good at following instructions, but not at reading your mind.",
|
||||||
|
"author": "Donald Knuth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A good programmer is someone who always looks both ways before crossing a one-way street.",
|
||||||
|
"author": "Doug Linder"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Tough times never last, but tough people do.",
|
||||||
|
"author": "Dr. Robert Schuller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If things start happening, don't worry, don't stew, just go right along and you'll start happening too.",
|
||||||
|
"author": "Dr. Seuss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do not go gentle into that good night. Rage, rage against the dying of the light.",
|
||||||
|
"author": "Dylan Thomas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The question of whether computers can think is like the question of whether submarines can swim.",
|
||||||
|
"author": "E.W. Dijkstra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Any code of your own that you haven't looked at for six or more months might as well have been written by someone else.",
|
||||||
|
"author": "Eagleson's Law"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do one thing every day that scares you.",
|
||||||
|
"author": "Eleanor Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "With the new day comes new strength and new thoughts.",
|
||||||
|
"author": "Eleanor Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You must do the things you think you cannot do.",
|
||||||
|
"author": "Eleanor Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Light tomorrow with today.",
|
||||||
|
"author": "Elizabeth Barrett Browning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Forever is composed of nows.",
|
||||||
|
"author": "Emily Dickinson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter.",
|
||||||
|
"author": "Eric Raymond"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you don't risk anything, you risk even more.",
|
||||||
|
"author": "Erica Jong"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The world breaks everyone, and afterward, many are strong at the broken places.",
|
||||||
|
"author": "Ernest Hemingway"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is nothing noble in being superior to your fellow man; true nobility is being superior to your former self.",
|
||||||
|
"author": "Ernest Hemingway"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Never confuse a single defeat with a final defeat.",
|
||||||
|
"author": "F. Scott Fitzgerald"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I attribute my success to this - I never gave or took any excuse.",
|
||||||
|
"author": "Florence Nightingale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The best revenge is massive success.",
|
||||||
|
"author": "Frank Sinatra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The only limit to our realization of tomorrow, will be our doubts of today.",
|
||||||
|
"author": "Franklin D. Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Right or wrong, it's very pleasant to break something from time to time.",
|
||||||
|
"author": "Fyodor Dostoevsky"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The harder I work, the luckier I get.",
|
||||||
|
"author": "Gary Player"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Giving up is the only sure way to fail.",
|
||||||
|
"author": "Gena Showalter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards.",
|
||||||
|
"author": "Gene Spafford"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing.",
|
||||||
|
"author": "George Bernard Shaw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack.",
|
||||||
|
"author": "George Carrette"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Discovering the unexpected is more important than confirming the known.",
|
||||||
|
"author": "George Box"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We only see what we know.",
|
||||||
|
"author": "Goethe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Without hard work, nothing grows but weeds.",
|
||||||
|
"author": "Gordon B. Hinckley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The function of good software is to make the complex appear to be simple.",
|
||||||
|
"author": "Grady Booch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "When you know that you're capable of dealing with whatever comes, you have the only security the world has to offer.",
|
||||||
|
"author": "Harry Browne"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Pain is inevitable. Suffering is optional.",
|
||||||
|
"author": "Haruki Murakami"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence.",
|
||||||
|
"author": "Helen Keller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The price of anything is the amount of life you exchange for it.",
|
||||||
|
"author": "Henry David Thoreau"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Whether you think you can or think you can't, you're right.",
|
||||||
|
"author": "Henry Ford"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The most exciting phrase to hear in science, the one that heralds discoveries, is not 'Eureka!' but 'Now that's funny…'",
|
||||||
|
"author": "Isaac Asimov"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We are all failures. At least the best of us are.",
|
||||||
|
"author": "J.M. Barrie"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can't wait for inspiration. You have to go after it with a club.",
|
||||||
|
"author": "Jack London"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't wish it were easier, wish you were better.",
|
||||||
|
"author": "Jim Rohn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "By seeking and blundering we learn.",
|
||||||
|
"author": "Johann Wolfgang von Goethe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Knowing is not enough; we must apply. Wishing is not enough; we must do.",
|
||||||
|
"author": "Johann Wolfgang von Goethe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We first make our habits, then our habits make us.",
|
||||||
|
"author": "John Dryden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The power of imagination makes us infinite.",
|
||||||
|
"author": "John Muir"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "May you live every day of your life.",
|
||||||
|
"author": "Jonathan Swift"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Perseverance is failing 19 times and succeeding the 20th.",
|
||||||
|
"author": "Julie Andrews"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The work of today is the history of tomorrow, and we are its makers.",
|
||||||
|
"author": "Juliette Gordon Low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you reveal your secrets to the wind, you should not blame the wind for revealing them to the trees.",
|
||||||
|
"author": "Kahlil Gibran"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Optimism is an occupational hazard of programming; feedback is the treatment.",
|
||||||
|
"author": "Kent Beck"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Opportunity does not knock, it presents itself when you beat down the door.",
|
||||||
|
"author": "Kyle Chandler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "To iterate is human, to recurse divine.",
|
||||||
|
"author": "Peter Deutsch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A good traveler has no fixed plans and is not intent on arriving.",
|
||||||
|
"author": "Lao Tzu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "An ant on the move does more than a dozing ox.",
|
||||||
|
"author": "Lao Tzu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step.",
|
||||||
|
"author": "Lao Tzu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "That's the thing about people who think they hate computers. What they really hate is lousy programmers.",
|
||||||
|
"author": "Larry Niven"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It had long since come to my attention that people of accomplishment rarely sat back and let things happen to them. They went out and happened to things.",
|
||||||
|
"author": "Leonardo da Vinci"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you're any good at all, you know you can be better.",
|
||||||
|
"author": "Lindsay Buckingham"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If people never did silly things, nothing intelligent would ever get done.",
|
||||||
|
"author": "Ludwig Wittgenstein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You only live once, but if you do it right, once is enough.",
|
||||||
|
"author": "Mae West"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Live as if you were to die tomorrow. Learn as if you were to live forever.",
|
||||||
|
"author": "Mahatma Gandhi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Strength does not come from physical capacity. It comes from an indomitable will.",
|
||||||
|
"author": "Mahatma Gandhi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "One person's 'paranoia' is another person's 'engineering redundancy'.",
|
||||||
|
"author": "Marcus J. Ranum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less.",
|
||||||
|
"author": "Marie Curie"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you have everything under control, you're not moving fast enough.",
|
||||||
|
"author": "Mario Andretti"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Education: the path from cocky ignorance to miserable uncertainty.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It ain't what you don't know that gets you into trouble. It's what you know for sure that just ain't so.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The secret of getting ahead is getting started.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The two most important days in your life are the day you are born and the day you find out why.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails.",
|
||||||
|
"author": "Mark Twain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
|
||||||
|
"author": "Martin Fowler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I know, somehow, that only when it is dark enough can you see the stars.",
|
||||||
|
"author": "Martin Luther King Jr."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is never too late to be what you might have been.",
|
||||||
|
"author": "Mary Anne Evans"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Nothing will work unless you do.",
|
||||||
|
"author": "Maya Angelou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty.",
|
||||||
|
"author": "Maya Angelou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We may encounter many defeats, but we must not be defeated.",
|
||||||
|
"author": "Maya Angelou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Everybody has talent, but ability takes hard work.",
|
||||||
|
"author": "Michael Jordan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I've missed more than 9,000 shots during my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed.",
|
||||||
|
"author": "Michael Jordan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Impossible is just a big word thrown around by small men who find it easier to live in the world they've been given than to explore the power they have to change it. Impossible is not a fact. It's an opinion. Impossible is not a declaration. It's a dare. Impossible is potential. Impossible is temporary. Impossible is nothing.",
|
||||||
|
"author": "Muhammad Ali"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "A winner is a dreamer who never gives up.",
|
||||||
|
"author": "Nelson Mandela"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It always seems impossible until it's done.",
|
||||||
|
"author": "Nelson Mandela"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Failure will never overtake me if my determination to succeed is strong enough.",
|
||||||
|
"author": "Og Mandino"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I am not young enough to know everything.",
|
||||||
|
"author": "Oscar Wilde"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is only one thing that makes a dream impossible to achieve: the fear of failure.",
|
||||||
|
"author": "Paulo Coelho"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Never go to bed mad. Stay up and fight.",
|
||||||
|
"author": "Phyllis Diller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can't cross the sea merely by standing and staring at the water.",
|
||||||
|
"author": "Rabindranath Tagore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The only person you are destined to become is the person you decide to be.",
|
||||||
|
"author": "Ralph Waldo Emerson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "What you do speaks so loudly that I cannot hear what you say.",
|
||||||
|
"author": "Ralph Waldo Emerson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "People who are crazy enough to think they can change the world, are the ones who do.",
|
||||||
|
"author": "Rob Siltanen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The best way out is always through.",
|
||||||
|
"author": "Robert Frost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Today's accomplishments were yesterday's impossibilities.",
|
||||||
|
"author": "Robert H. Schuller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't be satisfied with stories, how things have gone with others. Unfold your own myth.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Forget safety. Live where you fear to live. Destroy your reputation. Be notorious.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Sell your cleverness and buy bewilderment.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The cure for pain is in the pain.",
|
||||||
|
"author": "Rumi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Have no fear of perfection - you'll never reach it.",
|
||||||
|
"author": "Salvador Dalí"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't watch the clock. Do what it does. Keep going.",
|
||||||
|
"author": "Sam Levenson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Ever Tried. Ever failed. No matter. Try again. Fail again. Fail better.",
|
||||||
|
"author": "Samuel Beckett"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The more you know, the more you realize you know nothing.",
|
||||||
|
"author": "Socrates"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.",
|
||||||
|
"author": "Stephen Hawking"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The universe doesn't allow perfection.",
|
||||||
|
"author": "Stephen Hawking"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Whether you want to uncover the secrets of the universe, or you want to pursue a career in the 21st century, basic computer programming is an essential skill to learn.",
|
||||||
|
"author": "Stephen Hawking"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The scariest moment is always just before you start.",
|
||||||
|
"author": "Stephen King"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can, you should, and if you're brave enough to start, you will.",
|
||||||
|
"author": "Stephen King"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Arise, Awake and Stop not until the goal is reached.",
|
||||||
|
"author": "Swami Vivekananda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is said that your life flashes before your eyes just before you die. That is true, it's called Life.",
|
||||||
|
"author": "Terry Pratchett"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Believe you can and you're halfway there.",
|
||||||
|
"author": "Theodore Roosevelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I have not failed. I've just found 10,000 ways that won't work.",
|
||||||
|
"author": "Thomas A. Edison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.",
|
||||||
|
"author": "Thomas A. Edison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The harder the conflict, the more glorious the triumph.",
|
||||||
|
"author": "Thomas Paine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The Web as I envisaged it, we have not seen it yet. The future is still so much bigger than the past.",
|
||||||
|
"author": "Tim Berners-Lee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Failure is the condiment that gives success its flavor.",
|
||||||
|
"author": "Truman Capote"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Those who says it cannot be done should not interrupt the person doing it.",
|
||||||
|
"author": "Unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Even if you fall on your face, you're still moving forward.",
|
||||||
|
"author": "Victor Kiam"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It's not whether you get knocked down, it's whether you get up.",
|
||||||
|
"author": "Vince Lombardi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I dream my painting and I paint my dream.",
|
||||||
|
"author": "Vincent van Gogh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Let us cultivate our garden.",
|
||||||
|
"author": "Voltaire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Aim for the moon. If you miss, you may hit a star.",
|
||||||
|
"author": "W. Clement Stone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The way to get started is to quit talking and begin doing.",
|
||||||
|
"author": "Walt Disney"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You miss 100% of the shots you don't take.",
|
||||||
|
"author": "Wayne Gretzky"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don't let yesterday take up too much of today.",
|
||||||
|
"author": "Will Rogers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Even if you're on the right track, you'll get run over if you just sit there.",
|
||||||
|
"author": "Will Rogers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Do not wait to strike till the iron is hot; but make it hot by striking.",
|
||||||
|
"author": "William Butler Yeats"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You cannot swim for new horizons until you have courage to lose sight of the shore.",
|
||||||
|
"author": "William Faulkner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Be not afraid of greatness. Some are born great, some achieve greatness, and others have greatness thrust upon them.",
|
||||||
|
"author": "William Shakespeare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We know what we are, but not what we may be.",
|
||||||
|
"author": "William Shakespeare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "In theory there is no difference between theory and practice. In practice there is.",
|
||||||
|
"author": "Yogi Berra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can see a lot by just looking.",
|
||||||
|
"author": "Yogi Berra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is no elevator to success, you have to take the stairs.",
|
||||||
|
"author": "Zig Ziglar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You don't have to be great to start, but you have to start to be great.",
|
||||||
|
"author": "Zig Ziglar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
62
client/i18n/locales/portuguese/trending.json
Normal file
62
client/i18n/locales/portuguese/trending.json
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"article0title":"10 to the Power of 0",
|
||||||
|
"article0link":"https://www.freecodecamp.org/news/10-to-the-power-of-0-the-zero-exponent-rule-and-the-power-of-zero-explained/",
|
||||||
|
"article1title":"Git Reset to Remote",
|
||||||
|
"article1link":"https://www.freecodecamp.org/news/git-reset-to-remote-head-how-to-reset-a-remote-branch-to-origin/",
|
||||||
|
"article2title":"R Value in Statistics",
|
||||||
|
"article2link":"https://www.freecodecamp.org/news/what-is-a-correlation-coefficient-r-value-in-statistics-explains/",
|
||||||
|
"article3title":"What is Economics?",
|
||||||
|
"article3link":"https://www.freecodecamp.org/news/what-is-economics/",
|
||||||
|
"article4title":"Module Exports",
|
||||||
|
"article4link":"https://www.freecodecamp.org/news/node-module-exports-explained-with-javascript-export-function-examples/",
|
||||||
|
"article5title":"Python VS JavaScript",
|
||||||
|
"article5link":"https://www.freecodecamp.org/news/python-vs-javascript-what-are-the-key-differences-between-the-two-popular-programming-languages/",
|
||||||
|
"article6title":"Model View Controller",
|
||||||
|
"article6link":"https://www.freecodecamp.org/news/model-view-architecture/",
|
||||||
|
"article7title":"React Testing Library",
|
||||||
|
"article7link":"https://www.freecodecamp.org/news/react-testing-library-tutorial-javascript-example-code/",
|
||||||
|
"article8title":"ASCII Table Chart",
|
||||||
|
"article8link":"https://www.freecodecamp.org/news/ascii-table-hex-to-ascii-value-character-code-chart-2/",
|
||||||
|
"article9title":"Data Validation",
|
||||||
|
"article9link":"https://www.freecodecamp.org/news/form-validation-with-html5-and-javascript/",
|
||||||
|
"article10title":"Recursion",
|
||||||
|
"article10link":"https://www.freecodecamp.org/news/what-is-recursion-in-javascript/",
|
||||||
|
"article11title":"ISO File",
|
||||||
|
"article11link":"https://www.freecodecamp.org/news/what-is-an-iso-file-explained-in-plain-english/",
|
||||||
|
"article12title":"ADB",
|
||||||
|
"article12link":"https://www.freecodecamp.org/news/adb-android-install-guide-drivers-and-commands/",
|
||||||
|
"article13title":"MBR VS GPT",
|
||||||
|
"article13link":"https://www.freecodecamp.org/news/mbr-vs-gpt-whats-the-difference-between-an-mbr-partition-and-a-gpt-partition-solved/",
|
||||||
|
"article14title":"Debounce",
|
||||||
|
"article14link":"https://www.freecodecamp.org/news/javascript-debounce-example/",
|
||||||
|
"article15title":"Helm Chart",
|
||||||
|
"article15link":"https://www.freecodecamp.org/news/what-is-a-helm-chart-tutorial-for-kubernetes-beginners/",
|
||||||
|
"article16title":"80-20 Rule",
|
||||||
|
"article16link":"https://www.freecodecamp.org/news/the-80-20-rule-pareto-principle-explained-in-plain-english/",
|
||||||
|
"article17title":"OSI Model",
|
||||||
|
"article17link":"https://www.freecodecamp.org/news/osi-model-networking-layers-explained-in-plain-english/",
|
||||||
|
"article18title":"HTML Link Code",
|
||||||
|
"article18link":"https://www.freecodecamp.org/news/html-link-code-how-to-insert-a-link-to-a-website-with-href-3/",
|
||||||
|
"article19title":"SDLC",
|
||||||
|
"article19link":"https://www.freecodecamp.org/news/what-is-sdlc-software-development-life-cycle-phases-methodologies-and-processes-explained/",
|
||||||
|
"article20title":"Inductive VS Deductive",
|
||||||
|
"article20link":"https://www.freecodecamp.org/news/inductive-vs-deductive-reasoning/",
|
||||||
|
"article21title":"JavaScript Empty Array",
|
||||||
|
"article21link":"https://www.freecodecamp.org/news/check-if-javascript-array-is-empty-or-not-with-length/",
|
||||||
|
"article22title":"Best Instagram Post Time",
|
||||||
|
"article22link":"https://www.freecodecamp.org/news/the-best-time-to-post-on-instagram-the-best-days-and-times-to-reach-your-ig-followers/",
|
||||||
|
"article23title":"Garbage Collection in Java",
|
||||||
|
"article23link":"https://www.freecodecamp.org/news/garbage-collection-in-java-what-is-gc-and-how-it-works-in-the-jvm/",
|
||||||
|
"article24title":"Auto-Numbering in Excel",
|
||||||
|
"article24link":"https://www.freecodecamp.org/news/auto-numbering-in-excel/",
|
||||||
|
"article25title":"JavaScript Keycode List",
|
||||||
|
"article25link":"https://www.freecodecamp.org/news/javascript-keycode-list-keypress-event-key-codes/",
|
||||||
|
"article26title":"JavaScript Reverse Array",
|
||||||
|
"article26link":"https://www.freecodecamp.org/news/javascript-array-reverse-tutorial-with-example-js-code/",
|
||||||
|
"article27title":"How to Screenshot on Mac",
|
||||||
|
"article27link":"https://www.freecodecamp.org/news/how-to-take-a-screenshot-on-a-mac-keyboard-shortcut/",
|
||||||
|
"article28title":"How to Reverse Image Search",
|
||||||
|
"article28link":"https://www.freecodecamp.org/news/how-to-reverse-image-search-on-your-phone-or-desktop/",
|
||||||
|
"article29title":"Ternary Operator JavaScript",
|
||||||
|
"article29link":"https://www.freecodecamp.org/news/ternary-operator-javascript-if-statement-tutorial/"
|
||||||
|
}
|
@ -18,6 +18,15 @@ const algoliaIndices = {
|
|||||||
'chinese-traditional': {
|
'chinese-traditional': {
|
||||||
name: 'news-zh',
|
name: 'news-zh',
|
||||||
searchPage: 'https://chinese.freecodecamp.org/news/search'
|
searchPage: 'https://chinese.freecodecamp.org/news/search'
|
||||||
|
},
|
||||||
|
// TODO: Replace with i18n pages when shipped
|
||||||
|
italian: {
|
||||||
|
name: 'news',
|
||||||
|
searchPage: 'https://www.freecodecamp.org/news/search/'
|
||||||
|
},
|
||||||
|
portuguese: {
|
||||||
|
name: 'news',
|
||||||
|
searchPage: 'https://www.freecodecamp.org/news/search/'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,8 +2,22 @@
|
|||||||
* from the .env file aren't found in their respective arrays below
|
* from the .env file aren't found in their respective arrays below
|
||||||
*/
|
*/
|
||||||
const availableLangs = {
|
const availableLangs = {
|
||||||
client: ['english', 'espanol', 'chinese', 'chinese-traditional'],
|
client: [
|
||||||
curriculum: ['english', 'espanol', 'chinese', 'chinese-traditional']
|
'english',
|
||||||
|
'espanol',
|
||||||
|
'chinese',
|
||||||
|
'chinese-traditional',
|
||||||
|
'italian',
|
||||||
|
'portuguese'
|
||||||
|
],
|
||||||
|
curriculum: [
|
||||||
|
'english',
|
||||||
|
'espanol',
|
||||||
|
'chinese',
|
||||||
|
'chinese-traditional',
|
||||||
|
'italian',
|
||||||
|
'portuguese'
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Each client language needs an entry in the rest of the variables below
|
// Each client language needs an entry in the rest of the variables below
|
||||||
@ -16,7 +30,9 @@ const i18nextCodes = {
|
|||||||
english: 'en',
|
english: 'en',
|
||||||
espanol: 'es',
|
espanol: 'es',
|
||||||
chinese: 'zh',
|
chinese: 'zh',
|
||||||
'chinese-traditional': 'zh-Hant'
|
'chinese-traditional': 'zh-Hant',
|
||||||
|
italian: 'it',
|
||||||
|
portuguese: 'pt-BR'
|
||||||
};
|
};
|
||||||
|
|
||||||
// These are for the language selector dropdown menu in the footer
|
// These are for the language selector dropdown menu in the footer
|
||||||
@ -24,7 +40,9 @@ const langDisplayNames = {
|
|||||||
english: 'English',
|
english: 'English',
|
||||||
espanol: 'Español',
|
espanol: 'Español',
|
||||||
chinese: '中文(简体字)',
|
chinese: '中文(简体字)',
|
||||||
'chinese-traditional': '中文(繁體字)'
|
'chinese-traditional': '中文(繁體字)',
|
||||||
|
italian: 'Italiano',
|
||||||
|
portuguese: 'Português'
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These are for formatting dates and numbers. Used with JS .toLocaleString().
|
/* These are for formatting dates and numbers. Used with JS .toLocaleString().
|
||||||
@ -35,7 +53,9 @@ const langCodes = {
|
|||||||
english: 'en-US',
|
english: 'en-US',
|
||||||
espanol: 'es-419',
|
espanol: 'es-419',
|
||||||
chinese: 'zh',
|
chinese: 'zh',
|
||||||
'chinese-traditional': 'zh-Hant'
|
'chinese-traditional': 'zh-Hant',
|
||||||
|
italian: 'it',
|
||||||
|
portuguese: 'pt-BR'
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.availableLangs = availableLangs;
|
exports.availableLangs = availableLangs;
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908849
|
||||||
|
title: Add Elements within Your Bootstrap Wells
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16636
|
||||||
|
dashedName: add-elements-within-your-bootstrap-wells
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now we're several `div` elements deep on each column of our row. This is as deep as we'll need to go. Now we can add our `button` elements.
|
||||||
|
|
||||||
|
Nest three `button` elements within each of your `div` elements having the class name `well`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Three `button` elements should be nested within each of your `div` elements with class `well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('div.well:eq(0)').children('button').length === 3 &&
|
||||||
|
$('div.well:eq(1)').children('button').length === 3
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should have a total of 6 `button` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button') && $('button').length > 5);
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `button` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/button>/g) &&
|
||||||
|
code.match(/<button/g) &&
|
||||||
|
code.match(/<\/button>/g).length === code.match(/<button/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,177 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aedc08845
|
||||||
|
title: Add Font Awesome Icons to all of our Buttons
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16637
|
||||||
|
required:
|
||||||
|
- link: 'https://use.fontawesome.com/releases/v5.8.1/css/all.css'
|
||||||
|
raw: true
|
||||||
|
dashedName: add-font-awesome-icons-to-all-of-our-buttons
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Font Awesome is a convenient library of icons. These icons can be web fonts or vector graphics. These icons are treated just like fonts. You can specify their size using pixels, and they will assume the font size of their parent HTML elements.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Use Font Awesome to add an `info-circle` icon to your info button and a `trash` icon to your delete button.
|
||||||
|
|
||||||
|
**Note:** The `span` element is an acceptable alternative to the `i` element for the directions below.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should add a `<i class="fas fa-info-circle"></i>` within your `info` button element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('.btn-info > i').is('.fas.fa-info-circle') ||
|
||||||
|
$('.btn-info > span').is('.fas.fa-info-circle')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should add a `<i class="fas fa-trash"></i>` within your `delete` button element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('.btn-danger > i').is('.fas.fa-trash') ||
|
||||||
|
$('.btn-danger > span').is('.fas.fa-trash')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your `i` elements should have a closing tag and `<i class="fas fa-thumbs-up"></i>` is in your `like` button element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/i>|<\/span/g) &&
|
||||||
|
code.match(/<\/i|<\/span>/g).length > 2 &&
|
||||||
|
($('.btn-primary > i').is('.fas.fa-thumbs-up') ||
|
||||||
|
$('.btn-primary > span').is('.fas.fa-thumbs-up'))
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fas fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fas fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fas fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fas fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,194 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aedd08845
|
||||||
|
title: Add Font Awesome Icons to our Buttons
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16638
|
||||||
|
required:
|
||||||
|
- link: 'https://use.fontawesome.com/releases/v5.8.1/css/all.css'
|
||||||
|
raw: true
|
||||||
|
dashedName: add-font-awesome-icons-to-our-buttons
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Font Awesome is a convenient library of icons. These icons can be webfonts or vector graphics. These icons are treated just like fonts. You can specify their size using pixels, and they will assume the font size of their parent HTML elements.
|
||||||
|
|
||||||
|
You can include Font Awesome in any app by adding the following code to the top of your HTML:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, we've already added it for you to this page behind the scenes.
|
||||||
|
|
||||||
|
The `i` element was originally used to make other elements italic, but is now commonly used for icons. You can add the Font Awesome classes to the `i` element to turn it into an icon, for example:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the `span` element is also acceptable for use with icons.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Use Font Awesome to add a `thumbs-up` icon to your like button by giving it an `i` element with the classes `fas` and `fa-thumbs-up`. Make sure to keep the text `Like` next to the icon.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should add an `i` element with the classes `fas` and `fa-thumbs-up`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('i').is('.fas.fa-thumbs-up') || $('span').is('.fas.fa-thumbs-up'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `fa-thumbs-up` icon should be located within the Like button.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
($('i.fa-thumbs-up').parent().text().match(/Like/gi) &&
|
||||||
|
$('.btn-primary > i').is('.fas.fa-thumbs-up')) ||
|
||||||
|
($('span.fa-thumbs-up').parent().text().match(/Like/gi) &&
|
||||||
|
$('.btn-primary > span').is('.fas.fa-thumbs-up'))
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `i` element should be nested within your `button` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('button').children('i').length > 0 ||
|
||||||
|
$('button').children('span').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your icon element should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/<\/i>|<\/span>/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fas fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,93 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908853
|
||||||
|
title: Add id Attributes to Bootstrap Elements
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16639
|
||||||
|
dashedName: add-id-attributes-to-bootstrap-elements
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Recall that in addition to class attributes, you can give each of your elements an `id` attribute.
|
||||||
|
|
||||||
|
Each id must be unique to a specific element and used only once per page.
|
||||||
|
|
||||||
|
Let's give a unique id to each of our `div` elements of class `well`.
|
||||||
|
|
||||||
|
Remember that you can give an element an id like this:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="well" id="center-well">
|
||||||
|
```
|
||||||
|
|
||||||
|
Give the well on the left the id of `left-well`. Give the well on the right the id of `right-well`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your left `well` should have the id of `left-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('.col-xs-6').children('#left-well') &&
|
||||||
|
$('.col-xs-6').children('#left-well').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your right `well` should have the id of `right-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('.col-xs-6').children('#right-well') &&
|
||||||
|
$('.col-xs-6').children('#right-well').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908850
|
||||||
|
title: Apply the Default Bootstrap Button Style
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16657
|
||||||
|
dashedName: apply-the-default-bootstrap-button-style
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Bootstrap has another button class called `btn-default`.
|
||||||
|
|
||||||
|
Apply both the `btn` and `btn-default` classes to each of your `button` elements.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should apply the `btn` class to each of your `button` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.btn').length > 5);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should apply the `btn-default` class to each of your `button` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.btn-default').length > 5);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
<button></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,175 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348cd8acef08813
|
||||||
|
title: Call out Optional Actions with btn-info
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16770
|
||||||
|
dashedName: call-out-optional-actions-with-btn-info
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Bootstrap comes with several pre-defined colors for buttons. The `btn-info` class is used to call attention to optional actions that the user can take.
|
||||||
|
|
||||||
|
Create a new block-level Bootstrap button below your `Like` button with the text `Info`, and add Bootstrap's `btn-info` and `btn-block` classes to it.
|
||||||
|
|
||||||
|
Note that these buttons still need the `btn` and `btn-block` classes.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should create a new `button` element with the text `Info`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('info', 'gi').test($('button').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
Both of your Bootstrap buttons should have the `btn` and `btn-block` classes.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button.btn-block.btn').length > 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your new button should have the class `btn-info`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('btn-info'));
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `button` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/button>/g) &&
|
||||||
|
code.match(/<button/g) &&
|
||||||
|
code.match(/<\/button>/g).length === code.match(/<button/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,157 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd8acde08812
|
||||||
|
title: Center Text with Bootstrap
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16771
|
||||||
|
dashedName: center-text-with-bootstrap
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now that we're using Bootstrap, we can center our heading element to make it look better. All we need to do is add the class `text-center` to our `h2` element.
|
||||||
|
|
||||||
|
Remember that you can add several classes to the same element by separating each of them with a space, like this:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h2 class="red-text text-center">your text</h2>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `h2` element should be centered by applying the class `text-center`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('h2').hasClass('text-center'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h2` element should still have the class `red-text`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('h2').hasClass('red-text'));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,185 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348cd8acef08812
|
||||||
|
title: Create a Block Element Bootstrap Button
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16810
|
||||||
|
dashedName: create-a-block-element-bootstrap-button
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Normally, your `button` elements with the `btn` and `btn-default` classes are only as wide as the text that they contain. For example:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button class="btn btn-default">Submit</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
This button would only be as wide as the word `Submit`.
|
||||||
|
|
||||||
|
<button class='btn btn-default'>Submit</button>
|
||||||
|
|
||||||
|
By making them block elements with the additional class of `btn-block`, your button will stretch to fill your page's entire horizontal space and any elements following it will flow onto a "new line" below the block.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button class="btn btn-default btn-block">Submit</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
This button would take up 100% of the available width.
|
||||||
|
|
||||||
|
<button class='btn btn-default btn-block'>Submit</button>
|
||||||
|
|
||||||
|
Note that these buttons still need the `btn` class.
|
||||||
|
|
||||||
|
Add Bootstrap's `btn-block` class to your Bootstrap button.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your button should still have the `btn` and `btn-default` classes.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('btn') && $('button').hasClass('btn-default'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your button should have the class `btn-block`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('btn-block'));
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `button` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/button>/g) &&
|
||||||
|
code.match(/<button/g) &&
|
||||||
|
code.match(/<\/button>/g).length === code.match(/<button/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-default">Like</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-block btn-default">Like</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,176 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348cd8acdf08812
|
||||||
|
title: Create a Bootstrap Button
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16811
|
||||||
|
dashedName: create-a-bootstrap-button
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Bootstrap has its own styles for `button` elements, which look much better than the plain HTML ones.
|
||||||
|
|
||||||
|
Create a new `button` element below your large kitten photo. Give it the `btn` and `btn-default` classes, as well as the text of `Like`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should create a new `button` element with the text `Like`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
new RegExp('like', 'gi').test($('button').text()) &&
|
||||||
|
$('img.img-responsive + button.btn').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your new button should have two classes: `btn` and `btn-default`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('btn') && $('button').hasClass('btn-default'));
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `button` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/button>/g) &&
|
||||||
|
code.match(/<button/g) &&
|
||||||
|
code.match(/<\/button>/g).length === code.match(/<button/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
|
||||||
|
<!-- ADD Bootstrap Styled Button -->
|
||||||
|
<button class="btn btn-default">Like</button>
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</html>
|
||||||
|
```
|
@ -0,0 +1,67 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908846
|
||||||
|
title: Create a Bootstrap Headline
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16812
|
||||||
|
dashedName: create-a-bootstrap-headline
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now let's build something from scratch to practice our HTML, CSS and Bootstrap skills.
|
||||||
|
|
||||||
|
We'll build a jQuery playground, which we'll soon put to use in our jQuery challenges.
|
||||||
|
|
||||||
|
To start with, create an `h3` element, with the text `jQuery Playground`.
|
||||||
|
|
||||||
|
Color your `h3` element with the `text-primary` Bootstrap class, and center it with the `text-center` Bootstrap class.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should add an `h3` element to your page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('h3') && $('h3').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h3` element should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/h3>/g) &&
|
||||||
|
code.match(/<h3/g) &&
|
||||||
|
code.match(/<\/h3>/g).length === code.match(/<h3/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h3` element should be colored by applying the class `text-primary`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('h3').hasClass('text-primary'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h3` element should be centered by applying the class `text-center`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('h3').hasClass('text-center'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h3` element should have the text `jQuery Playground`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.isTrue(/jquery(\s)+playground/gi.test($('h3').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
```
|
@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9bec908846
|
||||||
|
title: Create a Bootstrap Row
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16813
|
||||||
|
dashedName: create-a-bootstrap-row
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now we'll create a Bootstrap row for our inline elements.
|
||||||
|
|
||||||
|
Create a `div` element below the `h3` tag, with a class of `row`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should add a `div` element below your `h3` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('div').length > 1 &&
|
||||||
|
$('div.row h3.text-primary').length == 0 &&
|
||||||
|
$('div.row + h3.text-primary').length == 0 &&
|
||||||
|
$('h3.text-primary + div.row').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `div` element should have the class `row`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div').hasClass('row'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `row div` should be nested inside the `container-fluid div`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.container-fluid div.row').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `div` element should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row"></div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908852
|
||||||
|
title: Create a Class to Target with jQuery Selectors
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16815
|
||||||
|
dashedName: create-a-class-to-target-with-jquery-selectors
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Not every class needs to have corresponding CSS. Sometimes we create classes just for the purpose of selecting these elements more easily using jQuery.
|
||||||
|
|
||||||
|
Give each of your `button` elements the class `target`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should apply the `target` class to each of your `button` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.target').length > 5);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
<button class="btn btn-default"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="target btn btn-default"></button>
|
||||||
|
<button class="target btn btn-default"></button>
|
||||||
|
<button class="target btn btn-default"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well">
|
||||||
|
<button class="target btn btn-default"></button>
|
||||||
|
<button class="target btn btn-default"></button>
|
||||||
|
<button class="target btn btn-default"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,177 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aede08845
|
||||||
|
title: Create a Custom Heading
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16816
|
||||||
|
dashedName: create-a-custom-heading
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
We will make a simple heading for our Cat Photo App by putting the title and relaxing cat image in the same row.
|
||||||
|
|
||||||
|
Remember, Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a `div` element.
|
||||||
|
|
||||||
|
Nest your first image and your `h2` element within a single `<div class="row">` element. Nest your `h2` element within a `<div class="col-xs-8">` and your image in a `<div class="col-xs-4">` so that they are on the same line.
|
||||||
|
|
||||||
|
Notice how the image is now just the right size to fit along the text?
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `h2` element and topmost `img` element should both be nested together within a `div` element with the class `row`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.row:has(h2)').length > 0 && $('div.row:has(img)').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your topmost `img` element should be nested within a `div` with the class `col-xs-4`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('div.col-xs-4:has(img)').length > 0 &&
|
||||||
|
$('div.col-xs-4:has(div)').length === 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h2` element should be nested within a `div` with the class `col-xs-8`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('div.col-xs-8:has(h2)').length > 0 &&
|
||||||
|
$('div.col-xs-8:has(div)').length === 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `div` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908848
|
||||||
|
title: Create Bootstrap Wells
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 16825
|
||||||
|
dashedName: create-bootstrap-wells
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Bootstrap has a class called `well` that can create a visual sense of depth for your columns.
|
||||||
|
|
||||||
|
Nest one `div` element with the class `well` within each of your `col-xs-6` `div` elements.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should add a `div` element with the class `well` inside each of your `div` elements with the class `col-xs-6`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.col-xs-6').not(':has(>div.well)').length < 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
Both of your `div` elements with the class `col-xs-6` should be nested within your `div` element with the class `row`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.row > div.col-xs-6').length > 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
All your `div` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div class="well"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,188 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1347bd9aedf08845
|
||||||
|
title: Ditch Custom CSS for Bootstrap
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 17565
|
||||||
|
dashedName: ditch-custom-css-for-bootstrap
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
We can clean up our code and make our Cat Photo App look more conventional by using Bootstrap's built-in styles instead of the custom styles we created earlier.
|
||||||
|
|
||||||
|
Don't worry - there will be plenty of time to customize our CSS later.
|
||||||
|
|
||||||
|
Delete the `.red-text`, `p`, and `.smaller-image` CSS declarations from your `style` element so that the only declarations left in your `style` element are `h2` and `thick-green-border`.
|
||||||
|
|
||||||
|
Then delete the `p` element that contains a dead link. Then remove the `red-text` class from your `h2` element and replace it with the `text-primary` Bootstrap class.
|
||||||
|
|
||||||
|
Finally, remove the `smaller-image` class from your first `img` element and replace it with the `img-responsive` class.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `h2` element should no longer have the class `red-text`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!$('h2').hasClass('red-text'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h2` element should now have the class `text-primary`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('h2').hasClass('text-primary'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your paragraph elements should no longer use the font `Monospace`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
!$('p')
|
||||||
|
.css('font-family')
|
||||||
|
.match(/monospace/i)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `smaller-image` class should be removed from your top image.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!$('img').hasClass('smaller-image'));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should add the `img-responsive` class to your top image.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.img-responsive').length > 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908855
|
||||||
|
title: Give Each Element a Unique id
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18191
|
||||||
|
dashedName: give-each-element-a-unique-id
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
We will also want to be able to use jQuery to target each button by its unique id.
|
||||||
|
|
||||||
|
Give each of your buttons a unique id, starting with `target1` and ending with `target6`.
|
||||||
|
|
||||||
|
Make sure that `target1` to `target3` are in `#left-well`, and `target4` to `target6` are in `#right-well`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
One `button` element should have the id `target1`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#left-well').children('#target1') &&
|
||||||
|
$('#left-well').children('#target1').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
One `button` element should have the id `target2`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#left-well').children('#target2') &&
|
||||||
|
$('#left-well').children('#target2').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
One `button` element should have the id `target3`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#left-well').children('#target3') &&
|
||||||
|
$('#left-well').children('#target3').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
One `button` element should have the id `target4`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#right-well').children('#target4') &&
|
||||||
|
$('#right-well').children('#target4').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
One `button` element should have the id `target5`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#right-well').children('#target5') &&
|
||||||
|
$('#right-well').children('#target5').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
One `button` element should have the id `target6`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#right-well').children('#target6') &&
|
||||||
|
$('#right-well').children('#target6').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1"></button>
|
||||||
|
<button class="btn btn-default target" id="target2"></button>
|
||||||
|
<button class="btn btn-default target" id="target3"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4"></button>
|
||||||
|
<button class="btn btn-default target" id="target5"></button>
|
||||||
|
<button class="btn btn-default target" id="target6"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908746
|
||||||
|
title: House our page within a Bootstrap container-fluid div
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18198
|
||||||
|
dashedName: house-our-page-within-a-bootstrap-container-fluid-div
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now let's make sure all the content on your page is mobile-responsive.
|
||||||
|
|
||||||
|
Let's nest your `h3` element within a `div` element with the class `container-fluid`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `div` element should have the class `container-fluid`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div').hasClass('container-fluid'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your `div` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `h3` element should be nested inside a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div').children('h3').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,105 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908856
|
||||||
|
title: Label Bootstrap Buttons
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18222
|
||||||
|
dashedName: label-bootstrap-buttons
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Just like we labeled our wells, we want to label our buttons.
|
||||||
|
|
||||||
|
Give each of your `button` elements text that corresponds to its id selector.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `button` element with the id `target1` should have the text `#target1`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#target1', 'gi').test($('#target1').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `button` element with the id `target2` should have the text `#target2`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#target2', 'gi').test($('#target2').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `button` element with the id `target3` should have the text `#target3`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#target3', 'gi').test($('#target3').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `button` element with the id `target4` should have the text `#target4`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#target4', 'gi').test($('#target4').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `button` element with the id `target5` should have the text `#target5`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#target5', 'gi').test($('#target5').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `button` element with the id `target6` should have the text `#target6`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#target6', 'gi').test($('#target6').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1"></button>
|
||||||
|
<button class="btn btn-default target" id="target2"></button>
|
||||||
|
<button class="btn btn-default target" id="target3"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4"></button>
|
||||||
|
<button class="btn btn-default target" id="target5"></button>
|
||||||
|
<button class="btn btn-default target" id="target6"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,101 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908854
|
||||||
|
title: Label Bootstrap Wells
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18223
|
||||||
|
dashedName: label-bootstrap-wells
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
For the sake of clarity, let's label both of our wells with their ids.
|
||||||
|
|
||||||
|
Above your left-well, inside its `col-xs-6` `div` element, add a `h4` element with the text `#left-well`.
|
||||||
|
|
||||||
|
Above your right-well, inside its `col-xs-6` `div` element, add a `h4` element with the text `#right-well`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should add an `h4` element to each of your `<div class="col-xs-6">` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('.col-xs-6').children('h4') && $('.col-xs-6').children('h4').length > 1
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
One `h4` element should have the text `#left-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#left-well', 'gi').test($('h4').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
One `h4` element should have the text `#right-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('#right-well', 'gi').test($('h4').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `h4` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/h4>/g) &&
|
||||||
|
code.match(/<h4/g) &&
|
||||||
|
code.match(/<\/h4>/g).length === code.match(/<h4/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
<button class="btn btn-default target"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,214 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908845
|
||||||
|
title: Line up Form Elements Responsively with Bootstrap
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18225
|
||||||
|
required:
|
||||||
|
- link: >-
|
||||||
|
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css
|
||||||
|
raw: true
|
||||||
|
dashedName: line-up-form-elements-responsively-with-bootstrap
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now let's get your form `input` and your submission `button` on the same line. We'll do this the same way we have previously: by using a `div` element with the class `row`, and other `div` elements within it using the `col-xs-*` class.
|
||||||
|
|
||||||
|
Nest both your form's text `input` and submit `button` within a `div` with the class `row`. Nest your form's text `input` within a div with the class of `col-xs-7`. Nest your form's submit `button` in a `div` with the class `col-xs-5`.
|
||||||
|
|
||||||
|
This is the last challenge we'll do for our Cat Photo App for now. We hope you've enjoyed learning Font Awesome, Bootstrap, and responsive design!
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your form submission button and text input should be nested in a div with class `row`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('div.row:has(input[type="text"])').length > 0 &&
|
||||||
|
$('div.row:has(button[type="submit"])').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your form text input should be nested in a div with the class `col-xs-7`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.col-xs-7:has(input[type="text"])').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your form submission button should be nested in a div with the class `col-xs-5`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.col-xs-5:has(button[type="submit"])').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `div` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fa fa-paper-plane"></i> Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-7">
|
||||||
|
<input type="text" class="form-control" placeholder="cat photo URL" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-5">
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fa fa-paper-plane"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,176 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9acde08812
|
||||||
|
title: Make Images Mobile Responsive
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18232
|
||||||
|
dashedName: make-images-mobile-responsive
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
First, add a new image below the existing one. Set its `src` attribute to `https://bit.ly/fcc-running-cats`.
|
||||||
|
|
||||||
|
It would be great if this image could be exactly the width of our phone's screen.
|
||||||
|
|
||||||
|
Fortunately, with Bootstrap, all we need to do is add the `img-responsive` class to your image. Do this, and the image should perfectly fit the width of your page.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should have a total of two images.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('img').length === 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your new image should be below your old one and have the class `img-responsive`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('img:eq(1)').hasClass('img-responsive'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your new image should not have the class `smaller-image`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!$('img:eq(1)').hasClass('smaller-image'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your new image should have a `src` of `https://bit.ly/fcc-running-cats`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('img:eq(1)').attr('src') === 'https://bit.ly/fcc-running-cats');
|
||||||
|
```
|
||||||
|
|
||||||
|
Your new `img` element should have a closing angle bracket.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<img/g) &&
|
||||||
|
code.match(/<img[^<]*>/g).length === 2 &&
|
||||||
|
code.match(/<img/g).length === 2
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive">
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,191 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aeda08845
|
||||||
|
title: Responsively Style Checkboxes
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18269
|
||||||
|
required:
|
||||||
|
- link: >-
|
||||||
|
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css
|
||||||
|
raw: true
|
||||||
|
dashedName: responsively-style-checkboxes
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Since Bootstrap's `col-xs-*` classes are applicable to all `form` elements, you can use them on your checkboxes too! This way, the checkboxes will be evenly spread out across the page, regardless of how wide the screen resolution is.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Nest all three of your checkboxes in a `<div class="row">` element. Then nest each of them in a `<div class="col-xs-4">` element.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
All of your checkboxes should be nested inside one `div` with the class `row`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.row:has(input[type="checkbox"])').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your checkboxes should be nested inside its own `div` with the class `col-xs-4`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.col-xs-4:has(input[type="checkbox"])').length > 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `div` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,175 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aedb08845
|
||||||
|
title: Responsively Style Radio Buttons
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18270
|
||||||
|
required:
|
||||||
|
- link: >-
|
||||||
|
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css
|
||||||
|
raw: true
|
||||||
|
dashedName: responsively-style-radio-buttons
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You can use Bootstrap's `col-xs-*` classes on `form` elements, too! This way, our radio buttons will be evenly spread out across the page, regardless of how wide the screen resolution is.
|
||||||
|
|
||||||
|
Nest both your radio buttons within a `<div class="row">` element. Then nest each of them within a `<div class="col-xs-6">` element.
|
||||||
|
|
||||||
|
**Note:** As a reminder, radio buttons are `input` elements of type `radio`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
All of your radio buttons should be nested inside one `div` with the class `row`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.row:has(input[type="radio"])').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your radio buttons should be nested inside its own `div` with the class `col-xs-6`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.col-xs-6:has(input[type="radio"])').length > 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `div` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908847
|
||||||
|
title: Split Your Bootstrap Row
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18306
|
||||||
|
dashedName: split-your-bootstrap-row
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now that we have a Bootstrap Row, let's split it into two columns to house our elements.
|
||||||
|
|
||||||
|
Create two `div` elements within your row, both with the class `col-xs-6`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Two `div class="col-xs-6"` elements should be nested within your `div class="row"` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.row > div.col-xs-6').length > 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
All your `div` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6"></div>
|
||||||
|
<div class="col-xs-6"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,201 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed908845
|
||||||
|
title: Style Text Inputs as Form Controls
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18312
|
||||||
|
required:
|
||||||
|
- link: >-
|
||||||
|
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css
|
||||||
|
raw: true
|
||||||
|
dashedName: style-text-inputs-as-form-controls
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You can add the `fa-paper-plane` Font Awesome icon by adding `<i class="fa fa-paper-plane"></i>` within your submit `button` element.
|
||||||
|
|
||||||
|
Give your form's text input field a class of `form-control`. Give your form's submit button the classes `btn btn-primary`. Also give this button the Font Awesome icon of `fa-paper-plane`.
|
||||||
|
|
||||||
|
All textual `<input>`, `<textarea>`, and `<select>` elements with the class `.form-control` have a width of 100%.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The submit button in your form should have the classes `btn btn-primary`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button[type="submit"]').hasClass('btn btn-primary'));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should add a `<i class="fa fa-paper-plane"></i>` within your submit `button` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button[type="submit"]:has(i.fa.fa-paper-plane)').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
The text `input` in your form should have the class `form-control`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('input[type="text"]').hasClass('form-control'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your `i` elements should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/<\/i>/g) && code.match(/<\/i/g).length > 3);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary"><i class="fa fa-thumbs-up"></i> Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info"><i class="fa fa-info-circle"></i> Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger"><i class="fa fa-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love:</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fa fa-paper-plane"></i>Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,167 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348cd8acef08811
|
||||||
|
title: Taste the Bootstrap Button Color Rainbow
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18323
|
||||||
|
dashedName: taste-the-bootstrap-button-color-rainbow
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The `btn-primary` class is the main color you'll use in your app. It is useful for highlighting actions you want your user to take.
|
||||||
|
|
||||||
|
Replace Bootstrap's `btn-default` class with `btn-primary` in your button.
|
||||||
|
|
||||||
|
Note that this button will still need the `btn` and `btn-block` classes.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your button should have the class `btn-primary`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('btn-primary'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your button should still have the `btn` and `btn-block` classes.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('btn-block') && $('button').hasClass('btn'));
|
||||||
|
```
|
||||||
|
|
||||||
|
All your `button` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/button>/g) &&
|
||||||
|
code.match(/<button/g) &&
|
||||||
|
code.match(/<\/button>/g).length === code.match(/<button/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-default btn-block">Like</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-primary btn-block">Like</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,185 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aedf08845
|
||||||
|
title: Use a span to Target Inline Elements
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18370
|
||||||
|
dashedName: use-a-span-to-target-inline-elements
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You can use spans to create inline elements. Remember when we used the `btn-block` class to make the button fill the entire row?
|
||||||
|
|
||||||
|
<button class='btn' style='background-color: rgb(0, 100, 0); color: rgb(255, 255, 255);'>normal button</button>
|
||||||
|
|
||||||
|
<button class='btn btn-block' style='background-color: rgb(0, 100, 0); color: rgb(255, 255, 255);'>btn-block button</button>
|
||||||
|
|
||||||
|
That illustrates the difference between an "inline" element and a "block" element.
|
||||||
|
|
||||||
|
By using the inline `span` element, you can put several elements on the same line, and even style different parts of the same line differently.
|
||||||
|
|
||||||
|
Using a `span` element, nest the word `love` inside the `p` element that currently has the text `Things cats love`. Then give the `span` the class `text-danger` to make the text red.
|
||||||
|
|
||||||
|
Here's how you would do this for the `p` element that has the text `Top 3 things cats hate`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p>Top 3 things cats <span class="text-danger">hate:</span></p>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `span` element should be inside your `p` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('p span') && $('p span').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `span` element should have just the text `love`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('p span') &&
|
||||||
|
$('p span').text().match(/love/i) &&
|
||||||
|
!$('p span')
|
||||||
|
.text()
|
||||||
|
.match(/Things cats/i)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `span` element should have class `text-danger`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('span').hasClass('text-danger'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `span` element should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/span>/g) &&
|
||||||
|
code.match(/<span/g) &&
|
||||||
|
code.match(/<\/span>/g).length === code.match(/<span/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="text-primary text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<a href="#"><img class="img-responsive thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Things cats <span class="text-danger">love</span>:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,98 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aec908857
|
||||||
|
title: Use Comments to Clarify Code
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18347
|
||||||
|
dashedName: use-comments-to-clarify-code
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
When we start using jQuery, we will modify HTML elements without needing to actually change them in HTML.
|
||||||
|
|
||||||
|
Let's make sure that everyone knows they shouldn't actually modify any of this code directly.
|
||||||
|
|
||||||
|
Remember that you can start a comment with `<!--` and end a comment with `-->`
|
||||||
|
|
||||||
|
Add a comment at the top of your HTML that says `Code below this line should not be changed`
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should start a comment with `<!--` at the top of your HTML.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/^\s*<!--/));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your comment should have the text `Code below this line should not be changed`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/<!--(?!(>|->|.*-->.*this line))\s*.*this line.*\s*-->/gi));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should close your comment with `-->`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/-->.*\n+.+/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should have the same number of comment openers and closers.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/<!--/g).length === code.match(/-->/g).length);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Code below this line should not be changed -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,170 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9acde08712
|
||||||
|
title: Use Responsive Design with Bootstrap Fluid Containers
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18362
|
||||||
|
dashedName: use-responsive-design-with-bootstrap-fluid-containers
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
In the HTML5 and CSS section of freeCodeCamp we built a Cat Photo App. Now let's go back to it. This time, we'll style it using the popular Bootstrap responsive CSS framework.
|
||||||
|
|
||||||
|
Bootstrap will figure out how wide your screen is and respond by resizing your HTML elements - hence the name <dfn>responsive design</dfn>.
|
||||||
|
|
||||||
|
With responsive design, there is no need to design a mobile version of your website. It will look good on devices with screens of any width.
|
||||||
|
|
||||||
|
You can add Bootstrap to any app by adding the following code to the top of your HTML:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, we've already added it for you to this page behind the scenes. Note that using either `>` or `/>` to close the `link` tag is acceptable.
|
||||||
|
|
||||||
|
To get started, we should nest all of our HTML (except the `link` tag and the `style` element) in a `div` element with the class `container-fluid`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `div` element should have the class `container-fluid`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div').hasClass('container-fluid'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `div` element should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
All HTML elements after the closing `style` tag should be nested in `.container-fluid`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.container-fluid').children().length >= 8 && !$('.container-fluid').has("style").length && !$('.container-fluid').has("link").length);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h2 class="red-text">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,196 @@
|
|||||||
|
---
|
||||||
|
id: bad88fee1348ce8acef08815
|
||||||
|
title: Use the Bootstrap Grid to Put Elements Side By Side
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18371
|
||||||
|
dashedName: use-the-bootstrap-grid-to-put-elements-side-by-side
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Bootstrap uses a responsive 12-column grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a `div` element.
|
||||||
|
|
||||||
|
Bootstrap has different column width attributes that it uses depending on how wide the user's screen is. For example, phones have narrow screens, and laptops have wider screens.
|
||||||
|
|
||||||
|
Take for example Bootstrap's `col-md-*` class. Here, `md` means medium, and `*` is a number specifying how many columns wide the element should be. In this case, the column width of an element on a medium-sized screen, such as a laptop, is being specified.
|
||||||
|
|
||||||
|
In the Cat Photo App that we're building, we'll use `col-xs-*`, where `xs` means extra small (like an extra-small mobile phone screen), and `*` is the number of columns specifying how many columns wide the element should be.
|
||||||
|
|
||||||
|
Put the `Like`, `Info` and `Delete` buttons side-by-side by nesting all three of them within one `<div class="row">` element, then each of them within a `<div class="col-xs-4">` element.
|
||||||
|
|
||||||
|
The `row` class is applied to a `div`, and the buttons themselves can be nested within it.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your buttons should all be nested within the same `div` element with the class `row`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.row:has(button)').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your Bootstrap buttons should be nested within its own `div` element with the class `col-xs-4`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('div.col-xs-4:has(button)').length > 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your `button` elements should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/button>/g) &&
|
||||||
|
code.match(/<button/g) &&
|
||||||
|
code.match(/<\/button>/g).length === code.match(/<button/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each of your `div` elements should have a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/div>/g) &&
|
||||||
|
code.match(/<div/g) &&
|
||||||
|
code.match(/<\/div>/g).length === code.match(/<div/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,176 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348ce8acef08814
|
||||||
|
title: Warn Your Users of a Dangerous Action with btn-danger
|
||||||
|
challengeType: 0
|
||||||
|
forumTopicId: 18375
|
||||||
|
dashedName: warn-your-users-of-a-dangerous-action-with-btn-danger
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Bootstrap comes with several pre-defined colors for buttons. The `btn-danger` class is the button color you'll use to notify users that the button performs a destructive action, such as deleting a cat photo.
|
||||||
|
|
||||||
|
Create a button with the text `Delete` and give it the class `btn-danger`.
|
||||||
|
|
||||||
|
Note that these buttons still need the `btn` and `btn-block` classes.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should create a new `button` element with the text `Delete`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(new RegExp('Delete', 'gi').test($('button').text()));
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your Bootstrap buttons should have the `btn` and `btn-block` classes.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button.btn-block.btn').length > 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your new button should have the class `btn-danger`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('btn-danger'));
|
||||||
|
```
|
||||||
|
|
||||||
|
All of your `button` elements should have closing tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/button>/g) &&
|
||||||
|
code.match(/<button/g) &&
|
||||||
|
code.match(/<\/button>/g).length === code.match(/<button/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
.red-text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: Lobster, Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thick-green-border {
|
||||||
|
border-color: green;
|
||||||
|
border-width: 10px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smaller-image {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h2 class="red-text text-center">CatPhotoApp</h2>
|
||||||
|
|
||||||
|
<p>Click here for <a href="#">cat photos</a>.</p>
|
||||||
|
|
||||||
|
<a href="#"><img class="smaller-image thick-green-border" src="https://bit.ly/fcc-relaxing-cat" alt="A cute orange cat lying on its back."></a>
|
||||||
|
|
||||||
|
<img src="https://bit.ly/fcc-running-cats" class="img-responsive" alt="Three kittens running towards the camera.">
|
||||||
|
<button class="btn btn-block btn-primary">Like</button>
|
||||||
|
<button class="btn btn-block btn-info">Info</button>
|
||||||
|
<button class="btn btn-block btn-danger">Delete</button>
|
||||||
|
<p>Things cats love:</p>
|
||||||
|
<ul>
|
||||||
|
<li>cat nip</li>
|
||||||
|
<li>laser pointers</li>
|
||||||
|
<li>lasagna</li>
|
||||||
|
</ul>
|
||||||
|
<p>Top 3 things cats hate:</p>
|
||||||
|
<ol>
|
||||||
|
<li>flea treatment</li>
|
||||||
|
<li>thunder</li>
|
||||||
|
<li>other cats</li>
|
||||||
|
</ol>
|
||||||
|
<form action="https://freecatphotoapp.com/submit-cat-photo">
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Indoor</label>
|
||||||
|
<label><input type="radio" name="indoor-outdoor"> Outdoor</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Loving</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Lazy</label>
|
||||||
|
<label><input type="checkbox" name="personality"> Crazy</label>
|
||||||
|
<input type="text" placeholder="cat photo URL" required>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
id: bd7158d8c442eddfaeb5bd0f
|
||||||
|
title: Build a 25 + 5 Clock
|
||||||
|
challengeType: 3
|
||||||
|
forumTopicId: 301373
|
||||||
|
dashedName: build-a-25--5-clock
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/XpKrrW>.
|
||||||
|
|
||||||
|
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||||
|
|
||||||
|
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
||||||
|
|
||||||
|
**User Story #1:** I can see an element with `id="break-label"` that contains a string (e.g. "Break Length").
|
||||||
|
|
||||||
|
**User Story #2:** I can see an element with `id="session-label"` that contains a string (e.g. "Session Length").
|
||||||
|
|
||||||
|
**User Story #3:** I can see two clickable elements with corresponding IDs: `id="break-decrement"` and `id="session-decrement"`.
|
||||||
|
|
||||||
|
**User Story #4:** I can see two clickable elements with corresponding IDs: `id="break-increment"` and `id="session-increment"`.
|
||||||
|
|
||||||
|
**User Story #5:** I can see an element with a corresponding `id="break-length"`, which by default (on load) displays a value of 5.
|
||||||
|
|
||||||
|
**User Story #6:** I can see an element with a corresponding `id="session-length"`, which by default displays a value of 25.
|
||||||
|
|
||||||
|
**User Story #7:** I can see an element with a corresponding `id="timer-label"`, that contains a string indicating a session is initialized (e.g. "Session").
|
||||||
|
|
||||||
|
**User Story #8:** I can see an element with corresponding `id="time-left"`. NOTE: Paused or running, the value in this field should always be displayed in `mm:ss` format (i.e. 25:00).
|
||||||
|
|
||||||
|
**User Story #9:** I can see a clickable element with a corresponding `id="start_stop"`.
|
||||||
|
|
||||||
|
**User Story #10:** I can see a clickable element with a corresponding `id="reset"`.
|
||||||
|
|
||||||
|
**User Story #11:** When I click the element with the id of `reset`, any running timer should be stopped, the value within `id="break-length"` should return to `5`, the value within `id="session-length"` should return to 25, and the element with `id="time-left"` should reset to its default state.
|
||||||
|
|
||||||
|
**User Story #12:** When I click the element with the id of `break-decrement`, the value within `id="break-length"` decrements by a value of 1, and I can see the updated value.
|
||||||
|
|
||||||
|
**User Story #13:** When I click the element with the id of `break-increment`, the value within `id="break-length"` increments by a value of 1, and I can see the updated value.
|
||||||
|
|
||||||
|
**User Story #14:** When I click the element with the id of `session-decrement`, the value within `id="session-length"` decrements by a value of 1, and I can see the updated value.
|
||||||
|
|
||||||
|
**User Story #15:** When I click the element with the id of `session-increment`, the value within `id="session-length"` increments by a value of 1, and I can see the updated value.
|
||||||
|
|
||||||
|
**User Story #16:** I should not be able to set a session or break length to <= 0.
|
||||||
|
|
||||||
|
**User Story #17:** I should not be able to set a session or break length to > 60.
|
||||||
|
|
||||||
|
**User Story #18:** When I first click the element with `id="start_stop"`, the timer should begin running from the value currently displayed in `id="session-length"`, even if the value has been incremented or decremented from the original value of 25.
|
||||||
|
|
||||||
|
**User Story #19:** If the timer is running, the element with the id of `time-left` should display the remaining time in `mm:ss` format (decrementing by a value of 1 and updating the display every 1000ms).
|
||||||
|
|
||||||
|
**User Story #20:** If the timer is running and I click the element with `id="start_stop"`, the countdown should pause.
|
||||||
|
|
||||||
|
**User Story #21:** If the timer is paused and I click the element with `id="start_stop"`, the countdown should resume running from the point at which it was paused.
|
||||||
|
|
||||||
|
**User Story #22:** When a session countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of `timer-label` should display a string indicating a break has begun.
|
||||||
|
|
||||||
|
**User Story #23:** When a session countdown reaches zero (NOTE: timer MUST reach 00:00), a new break countdown should begin, counting down from the value currently displayed in the `id="break-length"` element.
|
||||||
|
|
||||||
|
**User Story #24:** When a break countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of `timer-label` should display a string indicating a session has begun.
|
||||||
|
|
||||||
|
**User Story #25:** When a break countdown reaches zero (NOTE: timer MUST reach 00:00), a new session countdown should begin, counting down from the value currently displayed in the `id="session-length"` element.
|
||||||
|
|
||||||
|
**User Story #26:** When a countdown reaches zero (NOTE: timer MUST reach 00:00), a sound indicating that time is up should play. This should utilize an HTML5 `audio` tag and have a corresponding `id="beep"`.
|
||||||
|
|
||||||
|
**User Story #27:** The audio element with `id="beep"` must be 1 second or longer.
|
||||||
|
|
||||||
|
**User Story #28:** The audio element with id of `beep` must stop playing and be rewound to the beginning when the element with the id of `reset` is clicked.
|
||||||
|
|
||||||
|
You can build your project by <a href='https://codepen.io/pen?template=MJjpwO' target='_blank' rel='nofollow'>using this CodePen template</a> and clicking `Save` to create your own pen. Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||||
|
|
||||||
|
Once you're done, submit the URL to your working project with all its tests passing.
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```js
|
||||||
|
// solution required
|
||||||
|
```
|
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
id: 587d7dbc367417b2b2512bae
|
||||||
|
title: Build a Drum Machine
|
||||||
|
challengeType: 3
|
||||||
|
forumTopicId: 301370
|
||||||
|
dashedName: build-a-drum-machine
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/MJyNMd>.
|
||||||
|
|
||||||
|
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||||
|
|
||||||
|
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
||||||
|
|
||||||
|
**User Story #1:** I should be able to see an outer container with a corresponding `id="drum-machine"` that contains all other elements.
|
||||||
|
|
||||||
|
**User Story #2:** Within `#drum-machine` I can see an element with a corresponding `id="display"`.
|
||||||
|
|
||||||
|
**User Story #3:** Within `#drum-machine` I can see 9 clickable drum pad elements, each with a class name of `drum-pad`, a unique id that describes the audio clip the drum pad will be set up to trigger, and an inner text that corresponds to one of the following keys on the keyboard: `Q`, `W`, `E`, `A`, `S`, `D`, `Z`, `X`, `C`. The drum pads MUST be in this order.
|
||||||
|
|
||||||
|
**User Story #4:** Within each `.drum-pad`, there should be an HTML5 `audio` element which has a `src` attribute pointing to an audio clip, a class name of `clip`, and an id corresponding to the inner text of its parent `.drum-pad` (e.g. `id="Q"`, `id="W"`, `id="E"` etc.).
|
||||||
|
|
||||||
|
**User Story #5:** When I click on a `.drum-pad` element, the audio clip contained in its child `audio` element should be triggered.
|
||||||
|
|
||||||
|
**User Story #6:** When I press the trigger key associated with each `.drum-pad`, the audio clip contained in its child `audio` element should be triggered (e.g. pressing the `Q` key should trigger the drum pad which contains the string `Q`, pressing the `W` key should trigger the drum pad which contains the string `W`, etc.).
|
||||||
|
|
||||||
|
**User Story #7:** When a `.drum-pad` is triggered, a string describing the associated audio clip is displayed as the inner text of the `#display` element (each string must be unique).
|
||||||
|
|
||||||
|
You can build your project by <a href='https://codepen.io/pen?template=MJjpwO' target='_blank' rel='nofollow'>using this CodePen template</a> and clicking `Save` to create your own pen. Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||||
|
|
||||||
|
Once you're done, submit the URL to your working project with all its tests passing.
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```js
|
||||||
|
// solution required
|
||||||
|
```
|
@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
id: bd7158d8c442eddfaeb5bd17
|
||||||
|
title: Build a JavaScript Calculator
|
||||||
|
challengeType: 3
|
||||||
|
forumTopicId: 301371
|
||||||
|
dashedName: build-a-javascript-calculator
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/wgGVVX>.
|
||||||
|
|
||||||
|
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||||
|
|
||||||
|
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
||||||
|
|
||||||
|
**User Story #1:** My calculator should contain a clickable element containing an `=` (equal sign) with a corresponding `id="equals"`.
|
||||||
|
|
||||||
|
**User Story #2:** My calculator should contain 10 clickable elements containing one number each from 0-9, with the following corresponding IDs: `id="zero"`, `id="one"`, `id="two"`, `id="three"`, `id="four"`, `id="five"`, `id="six"`, `id="seven"`, `id="eight"`, and `id="nine"`.
|
||||||
|
|
||||||
|
**User Story #3:** My calculator should contain 4 clickable elements each containing one of the 4 primary mathematical operators with the following corresponding IDs: `id="add"`, `id="subtract"`, `id="multiply"`, `id="divide"`.
|
||||||
|
|
||||||
|
**User Story #4:** My calculator should contain a clickable element containing a `.` (decimal point) symbol with a corresponding `id="decimal"`.
|
||||||
|
|
||||||
|
**User Story #5:** My calculator should contain a clickable element with an `id="clear"`.
|
||||||
|
|
||||||
|
**User Story #6:** My calculator should contain an element to display values with a corresponding `id="display"`.
|
||||||
|
|
||||||
|
**User Story #7:** At any time, pressing the `clear` button clears the input and output values, and returns the calculator to its initialized state; 0 should be shown in the element with the id of `display`.
|
||||||
|
|
||||||
|
**User Story #8:** As I input numbers, I should be able to see my input in the element with the id of `display`.
|
||||||
|
|
||||||
|
**User Story #9:** In any order, I should be able to add, subtract, multiply and divide a chain of numbers of any length, and when I hit `=`, the correct result should be shown in the element with the id of `display`.
|
||||||
|
|
||||||
|
**User Story #10:** When inputting numbers, my calculator should not allow a number to begin with multiple zeros.
|
||||||
|
|
||||||
|
**User Story #11:** When the decimal element is clicked, a `.` should append to the currently displayed value; two `.` in one number should not be accepted.
|
||||||
|
|
||||||
|
**User Story #12:** I should be able to perform any operation (`+`, `-`, `*`, `/`) on numbers containing decimal points.
|
||||||
|
|
||||||
|
**User Story #13:** If 2 or more operators are entered consecutively, the operation performed should be the last operator entered (excluding the negative (`-`) sign). For example, if `5 + * 7 =` is entered, the result should be `35` (i.e. `5 * 7`); if `5 * - 5 =` is entered, the result should be `-25` (i.e. `5 * (-5)`).
|
||||||
|
|
||||||
|
**User Story #14:** Pressing an operator immediately following `=` should start a new calculation that operates on the result of the previous evaluation.
|
||||||
|
|
||||||
|
**User Story #15:** My calculator should have several decimal places of precision when it comes to rounding (note that there is no exact standard, but you should be able to handle calculations like `2 / 7` with reasonable precision to at least 4 decimal places).
|
||||||
|
|
||||||
|
**Note On Calculator Logic:** It should be noted that there are two main schools of thought on calculator input logic: <dfn>immediate execution logic</dfn> and <dfn>formula logic</dfn>. Our example utilizes formula logic and observes order of operation precedence, immediate execution does not. Either is acceptable, but please note that depending on which you choose, your calculator may yield different results than ours for certain equations (see below example). As long as your math can be verified by another production calculator, please do not consider this a bug.
|
||||||
|
|
||||||
|
**EXAMPLE:** `3 + 5 x 6 - 2 / 4 =`
|
||||||
|
|
||||||
|
- **Immediate Execution Logic:** `11.5`
|
||||||
|
- **Formula/Expression Logic:** `32.5`
|
||||||
|
|
||||||
|
You can build your project by <a href='https://codepen.io/pen?template=MJjpwO' target='_blank' rel='nofollow'>using this CodePen template</a> and clicking `Save` to create your own pen. Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||||
|
|
||||||
|
Once you're done, submit the URL to your working project with all its tests passing.
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```js
|
||||||
|
// solution required
|
||||||
|
```
|
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
id: bd7157d8c242eddfaeb5bd13
|
||||||
|
title: Build a Markdown Previewer
|
||||||
|
challengeType: 3
|
||||||
|
forumTopicId: 301372
|
||||||
|
dashedName: build-a-markdown-previewer
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/GrZVVO>.
|
||||||
|
|
||||||
|
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||||
|
|
||||||
|
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
||||||
|
|
||||||
|
**User Story #1:** I can see a `textarea` element with a corresponding `id="editor"`.
|
||||||
|
|
||||||
|
**User Story #2:** I can see an element with a corresponding `id="preview"`.
|
||||||
|
|
||||||
|
**User Story #3:** When I enter text into the `#editor` element, the `#preview` element is updated as I type to display the content of the textarea.
|
||||||
|
|
||||||
|
**User Story #4:** When I enter GitHub flavored markdown into the `#editor` element, the text is rendered as HTML in the `#preview` element as I type (HINT: You don't need to parse Markdown yourself - you can import the Marked library for this: <https://cdnjs.com/libraries/marked>).
|
||||||
|
|
||||||
|
**User Story #5:** When my markdown previewer first loads, the default text in the `#editor` field should contain valid markdown that represents at least one of each of the following elements: a header (H1 size), a sub header (H2 size), a link, inline code, a code block, a list item, a blockquote, an image, and bolded text.
|
||||||
|
|
||||||
|
**User Story #6:** When my markdown previewer first loads, the default markdown in the `#editor` field should be rendered as HTML in the `#preview` element.
|
||||||
|
|
||||||
|
**Optional Bonus (you do not need to make this test pass):** My markdown previewer interprets carriage returns and renders them as `br` (line break) elements.
|
||||||
|
|
||||||
|
You can build your project by <a href='https://codepen.io/pen?template=MJjpwO' target='_blank' rel='nofollow'>using this CodePen template</a> and clicking `Save` to create your own pen. Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||||
|
|
||||||
|
Once you're done, submit the URL to your working project with all its tests passing.
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```js
|
||||||
|
// solution required
|
||||||
|
```
|
@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
id: bd7158d8c442eddfaeb5bd13
|
||||||
|
title: Build a Random Quote Machine
|
||||||
|
challengeType: 3
|
||||||
|
forumTopicId: 301374
|
||||||
|
dashedName: build-a-random-quote-machine
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/qRZeGZ>.
|
||||||
|
|
||||||
|
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||||
|
|
||||||
|
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
||||||
|
|
||||||
|
**User Story #1:** I can see a wrapper element with a corresponding `id="quote-box"`.
|
||||||
|
|
||||||
|
**User Story #2:** Within `#quote-box`, I can see an element with a corresponding `id="text"`.
|
||||||
|
|
||||||
|
**User Story #3:** Within `#quote-box`, I can see an element with a corresponding `id="author"`.
|
||||||
|
|
||||||
|
**User Story #4:** Within `#quote-box`, I can see a clickable element with a corresponding `id="new-quote"`.
|
||||||
|
|
||||||
|
**User Story #5:** Within `#quote-box`, I can see a clickable `a` element with a corresponding `id="tweet-quote"`.
|
||||||
|
|
||||||
|
**User Story #6:** On first load, my quote machine displays a random quote in the element with `id="text"`.
|
||||||
|
|
||||||
|
**User Story #7:** On first load, my quote machine displays the random quote's author in the element with `id="author"`.
|
||||||
|
|
||||||
|
**User Story #8:** When the `#new-quote` button is clicked, my quote machine should fetch a new quote and display it in the `#text` element.
|
||||||
|
|
||||||
|
**User Story #9:** My quote machine should fetch the new quote's author when the `#new-quote` button is clicked and display it in the `#author` element.
|
||||||
|
|
||||||
|
**User Story #10:** I can tweet the current quote by clicking on the `#tweet-quote` `a` element. This `a` element should include the `"twitter.com/intent/tweet"` path in its `href` attribute to tweet the current quote.
|
||||||
|
|
||||||
|
**User Story #11:** The `#quote-box` wrapper element should be horizontally centered. Please run tests with browser's zoom level at 100% and page maximized.
|
||||||
|
|
||||||
|
You can build your project by <a href='https://codepen.io/pen?template=MJjpwO' target='_blank' rel='nofollow'>using this CodePen template</a> and clicking `Save` to create your own pen. Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||||
|
|
||||||
|
Once you're done, submit the URL to your working project with all its tests passing.
|
||||||
|
|
||||||
|
**Note:** Twitter does not allow links to be loaded in an iframe. Try using the `target="_blank"` or `target="_top"` attribute on the `#tweet-quote` element if your tweet won't load. `target="_top"` will replace the current tab so make sure your work is saved.
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```js
|
||||||
|
// solution required
|
||||||
|
```
|
@ -0,0 +1,131 @@
|
|||||||
|
---
|
||||||
|
id: 564944c91be2204b269d51e3
|
||||||
|
title: Change Text Inside an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 16773
|
||||||
|
dashedName: change-text-inside-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Using jQuery, you can change the text between the start and end tags of an element. You can even change HTML markup.
|
||||||
|
|
||||||
|
jQuery has a function called `.html()` that lets you add HTML tags and text within an element. Any content previously within the element will be completely replaced with the content you provide using this function.
|
||||||
|
|
||||||
|
Here's how you would rewrite and emphasize the text of our heading:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("h3").html("<em>jQuery Playground</em>");
|
||||||
|
```
|
||||||
|
|
||||||
|
jQuery also has a similar function called `.text()` that only alters text without adding tags. In other words, this function will not evaluate any HTML tags passed to it, but will instead treat it as the text you want to replace the existing content with.
|
||||||
|
|
||||||
|
Change the button with id `target4` by emphasizing its text.
|
||||||
|
|
||||||
|
[View our news article for <em>](https://www.freecodecamp.org/news/html-elements-explained-what-are-html-tags/#em-element) to learn the difference between `<i>` and `<em>` and their uses.
|
||||||
|
|
||||||
|
Note that while the `<i>` tag has traditionally been used to emphasize text, it has since been adopted for use as a tag for icons. The `<em>` tag is now widely accepted as the tag for emphasis. Either will work for this challenge.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should emphasize the text in your `target4` button by adding HTML tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.isTrue(
|
||||||
|
/<em>|<i>\s*#target4\s*<\/em>|<\/i>/gi.test($('#target4').html())
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The text should otherwise remain unchanged.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#target4') && $('#target4').text().trim() === '#target4');
|
||||||
|
```
|
||||||
|
|
||||||
|
You should not alter any other text.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.isFalse(/<em>|<i>/gi.test($('h3').html()));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should be using `.html()` and not `.text()`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\.html\(/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should select `button id="target4"` with jQuery.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\$\(\s*?(\"|\')#target4(\"|\')\s*?\)\.html\(/));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target4").html('<em>#target4</em>');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed908826
|
||||||
|
title: Change the CSS of an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 16776
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: change-the-css-of-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
We can also change the CSS of an HTML element directly with jQuery.
|
||||||
|
|
||||||
|
jQuery has a function called `.css()` that allows you to change the CSS of an element.
|
||||||
|
|
||||||
|
Here's how we would change its color to blue:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("#target1").css("color", "blue");
|
||||||
|
```
|
||||||
|
|
||||||
|
This is slightly different from a normal CSS declaration, because the CSS property and its value are in quotes, and separated with a comma instead of a colon.
|
||||||
|
|
||||||
|
Delete your jQuery selectors, leaving an empty `document ready function`.
|
||||||
|
|
||||||
|
Select `target1` and change its color to red.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `target1` element should have red text.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#target1').css('color') === 'rgb(255, 0, 0)');
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/class.*animated/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
$("#target3").addClass("animated fadeOut");
|
||||||
|
$("button").removeClass("btn-default");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
$("#target3").addClass("animated fadeOut");
|
||||||
|
$("button").removeClass("btn-default");
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,121 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed508826
|
||||||
|
title: Clone an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 16780
|
||||||
|
dashedName: clone-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
In addition to moving elements, you can also copy them from one place to another.
|
||||||
|
|
||||||
|
jQuery has a function called `clone()` that makes a copy of an element.
|
||||||
|
|
||||||
|
For example, if we wanted to copy `target2` from our `left-well` to our `right-well`, we would use:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("#target2").clone().appendTo("#right-well");
|
||||||
|
```
|
||||||
|
|
||||||
|
Did you notice this involves sticking two jQuery functions together? This is called <dfn>function chaining</dfn> and it's a convenient way to get things done with jQuery.
|
||||||
|
|
||||||
|
Clone your `target5` element and append it to your `left-well`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `target5` element should be inside your `right-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#right-well').children('#target5').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
A copy of your `target5` element should also be inside your `left-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#left-well').children('#target5').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to move these elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/class.*animated/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aeda08726
|
||||||
|
title: Delete Your jQuery Functions
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 17561
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: delete-your-jquery-functions
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
These animations were cool at first, but now they're getting kind of distracting.
|
||||||
|
|
||||||
|
Delete all three of these jQuery functions from your `document ready function`, but leave your `document ready function` itself intact.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
All three of your jQuery functions should be deleted from your `document ready function`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\{\s*\}\);/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should leave your `script` element intact.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/<script>/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should leave your `$(document).ready(function() {` at the beginning of your `script` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\$\(document\)\.ready\(function\(\)\s?\{/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should leave the `document.ready` function's closing `})` intact.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/.*\s*\}\);/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should leave your `script` element closing tag intact.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/script>/g) &&
|
||||||
|
code.match(/<script/g) &&
|
||||||
|
code.match(/<\/script>/g).length === code.match(/<script/g).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
$("#target3").addClass("animated fadeOut");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,120 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed808826
|
||||||
|
title: Disable an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 17563
|
||||||
|
dashedName: disable-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You can also change the non-CSS properties of HTML elements with jQuery. For example, you can disable buttons.
|
||||||
|
|
||||||
|
When you disable a button, it will become grayed-out and can no longer be clicked.
|
||||||
|
|
||||||
|
jQuery has a function called `.prop()` that allows you to adjust the properties of elements.
|
||||||
|
|
||||||
|
Here's how you would disable all buttons:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("button").prop("disabled", true);
|
||||||
|
```
|
||||||
|
|
||||||
|
Disable only the `target1` button.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `target1` button should be disabled.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#target1') &&
|
||||||
|
$('#target1').prop('disabled') &&
|
||||||
|
code.match(/["']disabled["'],( true|true)/g)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
No other buttons should be disabled.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#target2') && !$('#target2').prop('disabled'));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/disabled[^<]*>/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9acdd08826
|
||||||
|
title: Learn How Script Tags and Document Ready Work
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18224
|
||||||
|
dashedName: learn-how-script-tags-and-document-ready-work
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now we're ready to learn jQuery, the most popular JavaScript tool of all time.
|
||||||
|
|
||||||
|
Before we can start using jQuery, we need to add some things to our HTML.
|
||||||
|
|
||||||
|
First, add a `script` element at the top of your page. Be sure to close it on the following line.
|
||||||
|
|
||||||
|
Your browser will run any JavaScript inside a `script` element, including jQuery.
|
||||||
|
|
||||||
|
Inside your `script` element, add this code: `$(document).ready(function() {` to your `script`. Then close it on the following line (still inside your `script` element) with: `});`
|
||||||
|
|
||||||
|
We'll learn more about `functions` later. The important thing to know is that code you put inside this `function` will run as soon as your browser has loaded your page.
|
||||||
|
|
||||||
|
This is important because without your `document ready function`, your code may run before your HTML is rendered, which would cause bugs.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should create a `script` element making sure it is valid and has a closing tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/<\/script\s*>/g) &&
|
||||||
|
code.match(
|
||||||
|
/<script(\sasync|\sdefer)*(\s(charset|src|type)\s*=\s*["\"]+[^"\"]*["\"]+)*(\sasync|\sdefer)*\s*>/g
|
||||||
|
) &&
|
||||||
|
code.match(/<\/script\s*>/g).length ===
|
||||||
|
code.match(
|
||||||
|
/<script(\sasync|\sdefer)*(\s(charset|src|type)\s*=\s*["\"]+[^"\"]*["\"]+)*(\sasync|\sdefer)*\s*>/g
|
||||||
|
).length
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should add `$(document).ready(function() {` to the beginning of your `script` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(
|
||||||
|
/\$\s*?\(\s*?document\s*?\)\.ready\s*?\(\s*?function\s*?\(\s*?\)\s*?\{/g
|
||||||
|
)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should close your `$(document).ready(function() {` function with `});`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\n*?\s*?\}\s*?\);/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,109 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed708826
|
||||||
|
title: Remove an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18262
|
||||||
|
dashedName: remove-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now let's remove an HTML element from your page using jQuery.
|
||||||
|
|
||||||
|
jQuery has a function called `.remove()` that will remove an HTML element entirely
|
||||||
|
|
||||||
|
Remove the `#target4` element from the page by using the `.remove()` function.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should use jQuery to remove your `target4` element from your page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#target4').length === 0 && code.match(/\$\(["']#target4["']\).remove\(\)/g)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to remove this element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/id="target4/g) &&
|
||||||
|
!code.match(/<!--.*id="target4".*-->/g) &&
|
||||||
|
$('#right-well').length > 0
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,121 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed918626
|
||||||
|
title: Remove Classes from an Element with jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18264
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: remove-classes-from-an-element-with-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
In the same way you can add classes to an element with jQuery's `addClass()` function, you can remove them with jQuery's `removeClass()` function.
|
||||||
|
|
||||||
|
Here's how you would do this for a specific button:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("#target2").removeClass("btn-default");
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's remove the `btn-default` class from all of our `button` elements.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `btn-default` class should be removed from all of your `button` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.btn-default').length === 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to remove this class from the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/btn btn-default/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only remove the `btn-default` class.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(
|
||||||
|
/\.[\v\s]*removeClass[\s\v]*\([\s\v]*('|")\s*btn-default\s*('|")[\s\v]*\)/gm
|
||||||
|
)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
$("#target3").addClass("animated fadeOut");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
$("#target3").addClass("animated fadeOut");
|
||||||
|
$("button").removeClass("btn-default");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,143 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed108826
|
||||||
|
title: Target a Specific Child of an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18315
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: target-a-specific-child-of-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You've seen why id attributes are so convenient for targeting with jQuery selectors. But you won't always have such neat ids to work with.
|
||||||
|
|
||||||
|
Fortunately, jQuery has some other tricks for targeting the right elements.
|
||||||
|
|
||||||
|
jQuery uses CSS Selectors to target elements. The `target:nth-child(n)` CSS selector allows you to select all the nth elements with the target class or element type.
|
||||||
|
|
||||||
|
Here's how you would give the third element in each well the bounce class:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$(".target:nth-child(3)").addClass("animated bounce");
|
||||||
|
```
|
||||||
|
|
||||||
|
Make the second child in each of your well elements bounce. You must select the elements' children with the `target` class.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The second element in your `target` elements should bounce.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('.target:nth-child(2)').hasClass('animated') &&
|
||||||
|
$('.target:nth-child(2)').hasClass('bounce')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Only two elements should bounce.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.animated.bounce').length === 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should use the `:nth-child()` selector to modify these elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\:nth-child\(/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/\$\(".target:nth-child\(2\)"\)/g) ||
|
||||||
|
code.match(/\$\('.target:nth-child\(2\)'\)/g) ||
|
||||||
|
code.match(/\$\(".target"\).filter\(":nth-child\(2\)"\)/g) ||
|
||||||
|
code.match(/\$\('.target'\).filter\(':nth-child\(2\)'\)/g)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
$("#right-well").children().css("color", "orange");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
$("#right-well").children().css("color", "orange");
|
||||||
|
$(".target:nth-child(2)").addClass("animated bounce");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aedc08826
|
||||||
|
title: Target Elements by Class Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18316
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: target-elements-by-class-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You see how we made all of your `button` elements bounce? We selected them with `$("button")`, then we added some CSS classes to them with `.addClass("animated bounce");`.
|
||||||
|
|
||||||
|
You just used jQuery's `.addClass()` function, which allows you to add classes to elements.
|
||||||
|
|
||||||
|
First, let's target your `div` elements with the class `well` by using the `$(".well")` selector.
|
||||||
|
|
||||||
|
Note that, just like with CSS declarations, you type a `.` before the class's name.
|
||||||
|
|
||||||
|
Then use jQuery's `.addClass()` function to add the classes `animated` and `shake`.
|
||||||
|
|
||||||
|
For example, you could make all the elements with the class `text-primary` shake by adding the following to your `document ready function`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$(".text-primary").addClass("animated shake");
|
||||||
|
```
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should use the jQuery `addClass()` function to give the classes `animated` and `shake` to all your elements with the class `well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('.well').hasClass('animated') && $('.well').hasClass('shake'));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/class\.\*animated/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,122 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aeda08826
|
||||||
|
title: Target Elements by id Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18317
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: target-elements-by-id-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You can also target elements by their id attributes.
|
||||||
|
|
||||||
|
First target your `button` element with the id `target3` by using the `$("#target3")` selector.
|
||||||
|
|
||||||
|
Note that, just like with CSS declarations, you type a `#` before the id's name.
|
||||||
|
|
||||||
|
Then use jQuery's `.addClass()` function to add the classes `animated` and `fadeOut`.
|
||||||
|
|
||||||
|
Here's how you'd make the `button` element with the id `target6` fade out:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("#target6").addClass("animated fadeOut");
|
||||||
|
```
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should select the `button` element with the `id` of `target3` and use the jQuery `addClass()` function to give it the class of `animated`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#target3').hasClass('animated'));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should target the element with the id `target3` and use the jQuery `addClass()` function to give it the class `fadeOut`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
($('#target3').hasClass('fadeOut') || $('#target3').hasClass('fadeout')) &&
|
||||||
|
code.match(/\$\(\s*.#target3.\s*\)/g)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/class.*animated/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
$(".well").addClass("animated shake");
|
||||||
|
$("#target3").addClass("animated fadeOut");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,138 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed008826
|
||||||
|
title: Target Even Elements Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18318
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: target-even-elements-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You can also target elements based on their positions using `:odd` or `:even` selectors.
|
||||||
|
|
||||||
|
Note that jQuery is zero-indexed which means the first element in a selection has a position of 0. This can be a little confusing as, counter-intuitively, `:odd` selects the second element (position 1), fourth element (position 3), and so on.
|
||||||
|
|
||||||
|
Here's how you would target all the odd elements with class `target` and give them classes:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$(".target:odd").addClass("animated shake");
|
||||||
|
```
|
||||||
|
|
||||||
|
Try selecting all the even `target` elements and giving them the classes of `animated` and `shake`. Remember that **even** refers to the position of elements with a zero-based system in mind.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
All of the `target` elements that jQuery considers to be even should shake.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('.target:even').hasClass('animated') && $('.target:even').hasClass('shake')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should use the `:even` selector to modify these elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\:even/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/\$\(".target:even"\)/g) ||
|
||||||
|
code.match(/\$\('.target:even'\)/g) ||
|
||||||
|
code.match(/\$\(".target"\).filter\(":even"\)/g) ||
|
||||||
|
code.match(/\$\('.target'\).filter\(':even'\)/g)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
$("#right-well").children().css("color", "orange");
|
||||||
|
$("#left-well").children().css("color", "green");
|
||||||
|
$(".target:nth-child(2)").addClass("animated bounce");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
$("#right-well").children().css("color", "orange");
|
||||||
|
$("#left-well").children().css("color", "green");
|
||||||
|
$(".target:nth-child(2)").addClass("animated bounce");
|
||||||
|
$(".target:even").addClass("animated shake");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9bedc08826
|
||||||
|
title: Target HTML Elements with Selectors Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18319
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: target-html-elements-with-selectors-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now we have a `document ready function`.
|
||||||
|
|
||||||
|
Now let's write our first jQuery statement. All jQuery functions start with a `$`, usually referred to as a dollar sign operator, or as bling.
|
||||||
|
|
||||||
|
jQuery often selects an HTML element with a <dfn>selector</dfn>, then does something to that element.
|
||||||
|
|
||||||
|
For example, let's make all of your `button` elements bounce. Just add this code inside your document ready function:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that we've already included both the jQuery library and the Animate.css library in the background so that you can use them in the editor. So you are using jQuery to apply the Animate.css `bounce` class to your `button` elements.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should use the jQuery `addClass()` function to give the classes `animated` and `bounce` to your `button` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('button').hasClass('animated') && $('button').hasClass('bounce'));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/class.*animated/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your jQuery code should be within the `$(document).ready();` function.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.replace(/\s/g, '').match(/\$\(document\)\.ready\(function\(\)\{\$/g)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated bounce");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed208826
|
||||||
|
title: Target the Children of an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18320
|
||||||
|
dashedName: target-the-children-of-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
When HTML elements are placed one level below another they are called <dfn>children</dfn> of that element. For example, the button elements in this challenge with the text `#target1`, `#target2`, and `#target3` are all children of the `<div class="well" id="left-well">` element.
|
||||||
|
|
||||||
|
jQuery has a function called `children()` that allows you to access the children of whichever element you've selected.
|
||||||
|
|
||||||
|
Here's an example of how you would use the `children()` function to give the children of your `left-well` element the color `blue`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("#left-well").children().css("color", "blue")
|
||||||
|
```
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Give all the children of your `right-well` element the color orange.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
All children of `#right-well` should have orange text.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#right-well').children().css('color') === 'rgb(255, 165, 0)');
|
||||||
|
```
|
||||||
|
|
||||||
|
You should use the `children()` function to modify these elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\.children\(\)\.css/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/<div class="well" id="right-well">/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
$("#right-well").children().css("color", "orange");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed308826
|
||||||
|
title: Target the Parent of an Element Using jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18321
|
||||||
|
dashedName: target-the-parent-of-an-element-using-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Every HTML element has a `parent` element from which it `inherits` properties.
|
||||||
|
|
||||||
|
For example, your `jQuery Playground` `h3` element has the parent element of `<div class="container-fluid">`, which itself has the parent `body`.
|
||||||
|
|
||||||
|
jQuery has a function called `parent()` that allows you to access the parent of whichever element you've selected.
|
||||||
|
|
||||||
|
Here's an example of how you would use the `parent()` function if you wanted to give the parent element of the `left-well` element a background color of blue:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("#left-well").parent().css("background-color", "blue")
|
||||||
|
```
|
||||||
|
|
||||||
|
Give the parent of the `#target1` element a background-color of red.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `left-well` element should have a red background.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#left-well').css('background-color') === 'red' ||
|
||||||
|
$('#left-well').css('background-color') === 'rgb(255, 0, 0)' ||
|
||||||
|
$('#left-well').css('background-color').toLowerCase() === '#ff0000' ||
|
||||||
|
$('#left-well').css('background-color').toLowerCase() === '#f00'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should use the `.parent()` function to modify this element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\.parent\s*\(\s*\)\s*\.css/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.parent()` method should be called on the `#target1` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/\$\s*?\(\s*?(?:'|")\s*?#target1\s*?(?:'|")\s*?\)\s*?\.parent/gi)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/<div class="well" id="left-well">/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
```
|
@ -0,0 +1,142 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed908626
|
||||||
|
title: Target the Same Element with Multiple jQuery Selectors
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18322
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: target-the-same-element-with-multiple-jquery-selectors
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now you know three ways of targeting elements: by type: `$("button")`, by class: `$(".btn")`, and by id `$("#target1")`.
|
||||||
|
|
||||||
|
Although it is possible to add multiple classes in a single `.addClass()` call, let's add them to the same element in *three separate ways*.
|
||||||
|
|
||||||
|
Using `.addClass()`, add only one class at a time to the same element, three different ways:
|
||||||
|
|
||||||
|
Add the `animated` class to all elements with type `button`.
|
||||||
|
|
||||||
|
Add the `shake` class to all the buttons with class `.btn`.
|
||||||
|
|
||||||
|
Add the `btn-primary` class to the button with id `#target1`.
|
||||||
|
|
||||||
|
**Note:** You should only be targeting one element and adding only one class at a time. Altogether, your three individual selectors will end up adding the three classes `shake`, `animated`, and `btn-primary` to `#target1`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your code should use the `$("button")` selector.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?button\s*?(?:'|")/gi));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your code should use the `$(".btn")` selector.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?\.btn\s*?(?:'|")/gi));
|
||||||
|
```
|
||||||
|
|
||||||
|
Your code should use the `$("#target1")` selector.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?#target1\s*?(?:'|")/gi));
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only add one class with each of your three selectors.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
code.match(/addClass/g) &&
|
||||||
|
code.match(/addClass\s*?\(\s*?('|")\s*?[\w-]+\s*?\1\s*?\)/g).length > 2
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `#target1` element should have the classes `animated`‚ `shake` and `btn-primary`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
$('#target1').hasClass('animated') &&
|
||||||
|
$('#target1').hasClass('shake') &&
|
||||||
|
$('#target1').hasClass('btn-primary')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to add these classes to the element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/class.*animated/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("button").addClass("animated");
|
||||||
|
$(".btn").addClass("shake");
|
||||||
|
$("#target1").addClass("btn-primary");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aed608826
|
||||||
|
title: Use appendTo to Move Elements with jQuery
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18340
|
||||||
|
dashedName: use-appendto-to-move-elements-with-jquery
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now let's try moving elements from one `div` to another.
|
||||||
|
|
||||||
|
jQuery has a function called `appendTo()` that allows you to select HTML elements and append them to another element.
|
||||||
|
|
||||||
|
For example, if we wanted to move `target4` from our right well to our left well, we would use:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$("#target4").appendTo("#left-well");
|
||||||
|
```
|
||||||
|
|
||||||
|
Move your `target2` element from your `left-well` to your `right-well`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
Your `target2` element should not be inside your `left-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#left-well').children('#target2').length === 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `target2` element should be inside your `right-well`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('#right-well').children('#target2').length > 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should only use jQuery to move these elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(!code.match(/class.*animated/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
id: bad87fee1348bd9aecb08826
|
||||||
|
title: Use jQuery to Modify the Entire Page
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 18361
|
||||||
|
required:
|
||||||
|
- link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css'
|
||||||
|
dashedName: use-jquery-to-modify-the-entire-page
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
We're done playing with our jQuery playground. Let's tear it down!
|
||||||
|
|
||||||
|
jQuery can target the `body` element as well.
|
||||||
|
|
||||||
|
Here's how we would make the entire body fade out: `$("body").addClass("animated fadeOut");`
|
||||||
|
|
||||||
|
But let's do something more dramatic. Add the classes `animated` and `hinge` to your `body` element.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
You should add the classes `animated` and `hinge` to your `body` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert($('body').hasClass('animated') && $('body').hasClass('hinge'));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
$("#right-well").children().css("color", "orange");
|
||||||
|
$("#left-well").children().css("color", "green");
|
||||||
|
$(".target:nth-child(2)").addClass("animated bounce");
|
||||||
|
$(".target:even").addClass("animated shake");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#target1").css("color", "red");
|
||||||
|
$("#target1").prop("disabled", true);
|
||||||
|
$("#target4").remove();
|
||||||
|
$("#target2").appendTo("#right-well");
|
||||||
|
$("#target5").clone().appendTo("#left-well");
|
||||||
|
$("#target1").parent().css("background-color", "red");
|
||||||
|
$("#right-well").children().css("color", "orange");
|
||||||
|
$("#left-well").children().css("color", "green");
|
||||||
|
$(".target:nth-child(2)").addClass("animated bounce");
|
||||||
|
$(".target:even").addClass("animated shake");
|
||||||
|
$("body").addClass("animated hinge");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Only change code above this line -->
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h3 class="text-primary text-center">jQuery Playground</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#left-well</h4>
|
||||||
|
<div class="well" id="left-well">
|
||||||
|
<button class="btn btn-default target" id="target1">#target1</button>
|
||||||
|
<button class="btn btn-default target" id="target2">#target2</button>
|
||||||
|
<button class="btn btn-default target" id="target3">#target3</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<h4>#right-well</h4>
|
||||||
|
<div class="well" id="right-well">
|
||||||
|
<button class="btn btn-default target" id="target4">#target4</button>
|
||||||
|
<button class="btn btn-default target" id="target5">#target5</button>
|
||||||
|
<button class="btn btn-default target" id="target6">#target6</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
@ -0,0 +1,156 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036147
|
||||||
|
title: Connect Redux to React
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301426
|
||||||
|
dashedName: connect-redux-to-react
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now that you've written both the `mapStateToProps()` and the `mapDispatchToProps()` functions, you can use them to map `state` and `dispatch` to the `props` of one of your React components. The `connect` method from React Redux can handle this task. This method takes two optional arguments, `mapStateToProps()` and `mapDispatchToProps()`. They are optional because you may have a component that only needs access to `state` but doesn't need to dispatch any actions, or vice versa.
|
||||||
|
|
||||||
|
To use this method, pass in the functions as arguments, and immediately call the result with your component. This syntax is a little unusual and looks like:
|
||||||
|
|
||||||
|
```js
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** If you want to omit one of the arguments to the `connect` method, you pass `null` in its place.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has the `mapStateToProps()` and `mapDispatchToProps()` functions and a new React component called `Presentational`. Connect this component to Redux with the `connect` method from the `ReactRedux` global object, and call it immediately on the `Presentational` component. Assign the result to a new `const` called `ConnectedComponent` that represents the connected component. That's it, now you're connected to Redux! Try changing either of `connect`'s arguments to `null` and observe the test results.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `Presentational` component should render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return mockedComponent.find('Presentational').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should receive a prop `messages` via `connect`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const props = mockedComponent.find('Presentational').props();
|
||||||
|
return props.messages === '__INITIAL__STATE__';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should receive a prop `submitNewMessage` via `connect`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const props = mockedComponent.find('Presentational').props();
|
||||||
|
return typeof props.submitNewMessage === 'function';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const store = Redux.createStore(
|
||||||
|
(state = '__INITIAL__STATE__', action) => state
|
||||||
|
);
|
||||||
|
class AppWrapper extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ReactRedux.Provider store = {store}>
|
||||||
|
<ConnectedComponent/>
|
||||||
|
</ReactRedux.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: 'ADD',
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
messages: state
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
submitNewMessage: (message) => {
|
||||||
|
dispatch(addMessage(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Presentational extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return <h3>This is a Presentational Component</h3>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const connect = ReactRedux.connect;
|
||||||
|
// Change code below this line
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: 'ADD',
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
messages: state
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
submitNewMessage: (message) => {
|
||||||
|
dispatch(addMessage(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Presentational extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return <h3>This is a Presentational Component</h3>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const connect = ReactRedux.connect;
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(Presentational);
|
||||||
|
```
|
@ -0,0 +1,300 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036148
|
||||||
|
title: Connect Redux to the Messages App
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301427
|
||||||
|
dashedName: connect-redux-to-the-messages-app
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now that you understand how to use `connect` to connect React to Redux, you can apply what you've learned to your React component that handles messages.
|
||||||
|
|
||||||
|
In the last lesson, the component you connected to Redux was named `Presentational`, and this wasn't arbitrary. This term *generally* refers to React components that are not directly connected to Redux. They are simply responsible for the presentation of UI and do this as a function of the props they receive. By contrast, container components are connected to Redux. These are typically responsible for dispatching actions to the store and often pass store state to child components as props.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has all the code you've written in this section so far. The only change is that the React component is renamed to `Presentational`. Create a new component held in a constant called `Container` that uses `connect` to connect the `Presentational` component to Redux. Then, in the `AppWrapper`, render the React Redux `Provider` component. Pass `Provider` the Redux `store` as a prop and render `Container` as a child. Once everything is setup, you will see the messages app rendered to the page again.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `AppWrapper` should render to the page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return mockedComponent.find('AppWrapper').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should render to page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return mockedComponent.find('Presentational').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should render an `h2`, `input`, `button`, and `ul` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const PresentationalComponent = mockedComponent.find('Presentational');
|
||||||
|
return (
|
||||||
|
PresentationalComponent.find('div').length === 1 &&
|
||||||
|
PresentationalComponent.find('h2').length === 1 &&
|
||||||
|
PresentationalComponent.find('button').length === 1 &&
|
||||||
|
PresentationalComponent.find('ul').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should receive `messages` from the Redux store as a prop.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const PresentationalComponent = mockedComponent.find('Presentational');
|
||||||
|
const props = PresentationalComponent.props();
|
||||||
|
return Array.isArray(props.messages);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should receive the `submitMessage` action creator as a prop.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const PresentationalComponent = mockedComponent.find('Presentational');
|
||||||
|
const props = PresentationalComponent.props();
|
||||||
|
return typeof props.submitNewMessage === 'function';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Redux:
|
||||||
|
const ADD = 'ADD';
|
||||||
|
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: ADD,
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageReducer = (state = [], action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
action.message
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = Redux.createStore(messageReducer);
|
||||||
|
|
||||||
|
// React:
|
||||||
|
class Presentational extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.submitMessage = this.submitMessage.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
submitMessage() {
|
||||||
|
this.setState((state) => {
|
||||||
|
const currentMessage = state.input;
|
||||||
|
return {
|
||||||
|
input: '',
|
||||||
|
messages: state.messages.concat(currentMessage)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange}/><br/>
|
||||||
|
<button onClick={this.submitMessage}>Submit</button>
|
||||||
|
<ul>
|
||||||
|
{this.state.messages.map( (message, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx}>{message}</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// React-Redux:
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return { messages: state }
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
submitNewMessage: (newMessage) => {
|
||||||
|
dispatch(addMessage(newMessage))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Provider = ReactRedux.Provider;
|
||||||
|
const connect = ReactRedux.connect;
|
||||||
|
|
||||||
|
// Define the Container component here:
|
||||||
|
|
||||||
|
|
||||||
|
class AppWrapper extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
// Complete the return statement:
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Redux:
|
||||||
|
const ADD = 'ADD';
|
||||||
|
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: ADD,
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageReducer = (state = [], action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
action.message
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = Redux.createStore(messageReducer);
|
||||||
|
|
||||||
|
// React:
|
||||||
|
class Presentational extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.submitMessage = this.submitMessage.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
submitMessage() {
|
||||||
|
this.setState((state) => {
|
||||||
|
const currentMessage = state.input;
|
||||||
|
return {
|
||||||
|
input: '',
|
||||||
|
messages: state.messages.concat(currentMessage)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange}/><br/>
|
||||||
|
<button onClick={this.submitMessage}>Submit</button>
|
||||||
|
<ul>
|
||||||
|
{this.state.messages.map( (message, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx}>{message}</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// React-Redux:
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return { messages: state }
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
submitNewMessage: (newMessage) => {
|
||||||
|
dispatch(addMessage(newMessage))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Provider = ReactRedux.Provider;
|
||||||
|
const connect = ReactRedux.connect;
|
||||||
|
|
||||||
|
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
|
||||||
|
|
||||||
|
class AppWrapper extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Provider store={store}>
|
||||||
|
<Container/>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,397 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036149
|
||||||
|
title: Extract Local State into Redux
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301428
|
||||||
|
dashedName: extract-local-state-into-redux
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You're almost done! Recall that you wrote all the Redux code so that Redux could control the state management of your React messages app. Now that Redux is connected, you need to extract the state management out of the `Presentational` component and into Redux. Currently, you have Redux connected, but you are handling the state locally within the `Presentational` component.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
In the `Presentational` component, first, remove the `messages` property in the local `state`. These messages will be managed by Redux. Next, modify the `submitMessage()` method so that it dispatches `submitNewMessage()` from `this.props`, and pass in the current message input from local `state` as an argument. Because you removed `messages` from local state, remove the `messages` property from the call to `this.setState()` here as well. Finally, modify the `render()` method so that it maps over the messages received from `props` rather than `state`.
|
||||||
|
|
||||||
|
Once these changes are made, the app will continue to function the same, except Redux manages the state. This example also illustrates how a component may have local `state`: your component still tracks user input locally in its own `state`. You can see how Redux provides a useful state management framework on top of React. You achieved the same result using only React's local state at first, and this is usually possible with simple apps. However, as your apps become larger and more complex, so does your state management, and this is the problem Redux solves.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `AppWrapper` should render to the page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return mockedComponent.find('AppWrapper').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should render to page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return mockedComponent.find('Presentational').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should render an `h2`, `input`, `button`, and `ul` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const PresentationalComponent = mockedComponent.find('Presentational');
|
||||||
|
return (
|
||||||
|
PresentationalComponent.find('div').length === 1 &&
|
||||||
|
PresentationalComponent.find('h2').length === 1 &&
|
||||||
|
PresentationalComponent.find('button').length === 1 &&
|
||||||
|
PresentationalComponent.find('ul').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should receive `messages` from the Redux store as a prop.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const PresentationalComponent = mockedComponent.find('Presentational');
|
||||||
|
const props = PresentationalComponent.props();
|
||||||
|
return Array.isArray(props.messages);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should receive the `submitMessage` action creator as a prop.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const PresentationalComponent = mockedComponent.find('Presentational');
|
||||||
|
const props = PresentationalComponent.props();
|
||||||
|
return typeof props.submitNewMessage === 'function';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The state of the `Presentational` component should contain one property, `input`, which is initialized to an empty string.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const PresentationalState = mockedComponent
|
||||||
|
.find('Presentational')
|
||||||
|
.instance().state;
|
||||||
|
return (
|
||||||
|
typeof PresentationalState.input === 'string' &&
|
||||||
|
Object.keys(PresentationalState).length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Typing in the `input` element should update the state of the `Presentational` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const testValue = '__MOCK__INPUT__';
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
const causeChange = (c, v) =>
|
||||||
|
c.find('input').simulate('change', { target: { value: v } });
|
||||||
|
let initialInput = mockedComponent.find('Presentational').find('input');
|
||||||
|
const changed = () => {
|
||||||
|
causeChange(mockedComponent, testValue);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const updated = await changed();
|
||||||
|
const updatedInput = updated.find('Presentational').find('input');
|
||||||
|
assert(
|
||||||
|
initialInput.props().value === '' &&
|
||||||
|
updatedInput.props().value === '__MOCK__INPUT__'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Dispatching the `submitMessage` on the `Presentational` component should update Redux store and clear the input in local state.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
let beforeProps = mockedComponent.find('Presentational').props();
|
||||||
|
const testValue = '__TEST__EVENT__INPUT__';
|
||||||
|
const causeChange = (c, v) =>
|
||||||
|
c.find('input').simulate('change', { target: { value: v } });
|
||||||
|
const changed = () => {
|
||||||
|
causeChange(mockedComponent, testValue);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const clickButton = () => {
|
||||||
|
mockedComponent.find('button').simulate('click');
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const afterChange = await changed();
|
||||||
|
const afterChangeInput = afterChange.find('input').props().value;
|
||||||
|
const afterClick = await clickButton();
|
||||||
|
const afterProps = mockedComponent.find('Presentational').props();
|
||||||
|
assert(
|
||||||
|
beforeProps.messages.length === 0 &&
|
||||||
|
afterChangeInput === testValue &&
|
||||||
|
afterProps.messages.pop() === testValue &&
|
||||||
|
afterClick.find('input').props().value === ''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Presentational` component should render the `messages` from the Redux store.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
let beforeProps = mockedComponent.find('Presentational').props();
|
||||||
|
const testValue = '__TEST__EVENT__INPUT__';
|
||||||
|
const causeChange = (c, v) =>
|
||||||
|
c.find('input').simulate('change', { target: { value: v } });
|
||||||
|
const changed = () => {
|
||||||
|
causeChange(mockedComponent, testValue);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const clickButton = () => {
|
||||||
|
mockedComponent.find('button').simulate('click');
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const afterChange = await changed();
|
||||||
|
const afterChangeInput = afterChange.find('input').props().value;
|
||||||
|
const afterClick = await clickButton();
|
||||||
|
const afterProps = mockedComponent.find('Presentational').props();
|
||||||
|
assert(
|
||||||
|
beforeProps.messages.length === 0 &&
|
||||||
|
afterChangeInput === testValue &&
|
||||||
|
afterProps.messages.pop() === testValue &&
|
||||||
|
afterClick.find('input').props().value === '' &&
|
||||||
|
afterClick.find('ul').childAt(0).text() === testValue
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Redux:
|
||||||
|
const ADD = 'ADD';
|
||||||
|
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: ADD,
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageReducer = (state = [], action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
action.message
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = Redux.createStore(messageReducer);
|
||||||
|
|
||||||
|
// React:
|
||||||
|
const Provider = ReactRedux.Provider;
|
||||||
|
const connect = ReactRedux.connect;
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
class Presentational extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.submitMessage = this.submitMessage.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
submitMessage() {
|
||||||
|
this.setState((state) => ({
|
||||||
|
input: '',
|
||||||
|
messages: state.messages.concat(state.input)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange}/><br/>
|
||||||
|
<button onClick={this.submitMessage}>Submit</button>
|
||||||
|
<ul>
|
||||||
|
{this.state.messages.map( (message, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx}>{message}</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Change code above this line
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return {messages: state}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
submitNewMessage: (message) => {
|
||||||
|
dispatch(addMessage(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
|
||||||
|
|
||||||
|
class AppWrapper extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Provider store={store}>
|
||||||
|
<Container/>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Redux:
|
||||||
|
const ADD = 'ADD';
|
||||||
|
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: ADD,
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageReducer = (state = [], action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
action.message
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = Redux.createStore(messageReducer);
|
||||||
|
|
||||||
|
// React:
|
||||||
|
const Provider = ReactRedux.Provider;
|
||||||
|
const connect = ReactRedux.connect;
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
class Presentational extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: ''
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.submitMessage = this.submitMessage.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
submitMessage() {
|
||||||
|
this.props.submitNewMessage(this.state.input);
|
||||||
|
this.setState({
|
||||||
|
input: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange}/><br/>
|
||||||
|
<button onClick={this.submitMessage}>Submit</button>
|
||||||
|
<ul>
|
||||||
|
{this.props.messages.map( (message, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx}>{message}</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Change code above this line
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return {messages: state}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
submitNewMessage: (message) => {
|
||||||
|
dispatch(addMessage(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
|
||||||
|
|
||||||
|
class AppWrapper extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Provider store={store}>
|
||||||
|
<Container/>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,115 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036143
|
||||||
|
title: Extract State Logic to Redux
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301429
|
||||||
|
dashedName: extract-state-logic-to-redux
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now that you finished the React component, you need to move the logic it's performing locally in its `state` into Redux. This is the first step to connect the simple React app to Redux. The only functionality your app has is to add new messages from the user to an unordered list. The example is simple in order to demonstrate how React and Redux work together.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
First, define an action type `ADD` and set it to a const `ADD`. Next, define an action creator `addMessage()` which creates the action to add a message. You'll need to pass a `message` to this action creator and include the message in the returned `action`.
|
||||||
|
|
||||||
|
Then create a reducer called `messageReducer()` that handles the state for the messages. The initial state should equal an empty array. This reducer should add a message to the array of messages held in state, or return the current state. Finally, create your Redux store and pass it the reducer.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The const `ADD` should exist and hold a value equal to the string `ADD`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(ADD === 'ADD');
|
||||||
|
```
|
||||||
|
|
||||||
|
The action creator `addMessage` should return an object with `type` equal to `ADD` and `message` equal to the message that is passed in.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const addAction = addMessage('__TEST__MESSAGE__');
|
||||||
|
return addAction.type === ADD && addAction.message === '__TEST__MESSAGE__';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
`messageReducer` should be a function.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(typeof messageReducer === 'function');
|
||||||
|
```
|
||||||
|
|
||||||
|
The store should exist and have an initial state set to an empty array.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const initialState = store.getState();
|
||||||
|
return typeof store === 'object' && initialState.length === 0;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Dispatching `addMessage` against the store should immutably add a new message to the array of messages held in state.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const initialState = store.getState();
|
||||||
|
const isFrozen = DeepFreeze(initialState);
|
||||||
|
store.dispatch(addMessage('__A__TEST__MESSAGE'));
|
||||||
|
const addState = store.getState();
|
||||||
|
return isFrozen && addState[0] === '__A__TEST__MESSAGE';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `messageReducer` should return the current state if called with any other actions.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const addState = store.getState();
|
||||||
|
store.dispatch({ type: 'FAKE_ACTION' });
|
||||||
|
const testState = store.getState();
|
||||||
|
return addState === testState;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Define ADD, addMessage(), messageReducer(), and store here:
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const ADD = 'ADD';
|
||||||
|
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: ADD,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageReducer = (state = [], action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
action.message
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = Redux.createStore(messageReducer);
|
||||||
|
```
|
@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036141
|
||||||
|
title: Getting Started with React Redux
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301430
|
||||||
|
dashedName: getting-started-with-react-redux
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
This series of challenges introduces how to use Redux with React. First, here's a review of some of the key principles of each technology. React is a view library that you provide with data, then it renders the view in an efficient, predictable way. Redux is a state management framework that you can use to simplify the management of your application's state. Typically, in a React Redux app, you create a single Redux store that manages the state of your entire app. Your React components subscribe to only the pieces of data in the store that are relevant to their role. Then, you dispatch actions directly from React components, which then trigger store updates.
|
||||||
|
|
||||||
|
Although React components can manage their own state locally, when you have a complex app, it's generally better to keep the app state in a single location with Redux. There are exceptions when individual components may have local state specific only to them. Finally, because Redux is not designed to work with React out of the box, you need to use the `react-redux` package. It provides a way for you to pass Redux `state` and `dispatch` to your React components as `props`.
|
||||||
|
|
||||||
|
Over the next few challenges, first, you'll create a simple React component which allows you to input new text messages. These are added to an array that's displayed in the view. This should be a nice review of what you learned in the React lessons. Next, you'll create a Redux store and actions that manage the state of the messages array. Finally, you'll use `react-redux` to connect the Redux store with your component, thereby extracting the local state into the Redux store.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Start with a `DisplayMessages` component. Add a constructor to this component and initialize it with a state that has two properties: `input`, that's set to an empty string, and `messages`, that's set to an empty array.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `DisplayMessages` component should render an empty `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
return mockedComponent.find('div').text() === '';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `DisplayMessages` constructor should be called properly with `super`, passing in `props`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(getUserInput) =>
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const noWhiteSpace = __helpers.removeWhiteSpace(getUserInput('index'));
|
||||||
|
return (
|
||||||
|
noWhiteSpace.includes('constructor(props)') &&
|
||||||
|
noWhiteSpace.includes('super(props')
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `DisplayMessages` component should have an initial state equal to `{input: "", messages: []}`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
const initialState = mockedComponent.state();
|
||||||
|
return (
|
||||||
|
typeof initialState === 'object' &&
|
||||||
|
initialState.input === '' &&
|
||||||
|
Array.isArray(initialState.messages) &&
|
||||||
|
initialState.messages.length === 0
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<DisplayMessages />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class DisplayMessages extends React.Component {
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
render() {
|
||||||
|
return <div />
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class DisplayMessages extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return <div/>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,260 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036142
|
||||||
|
title: Manage State Locally First
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301431
|
||||||
|
dashedName: manage-state-locally-first
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Here you'll finish creating the `DisplayMessages` component.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
First, in the `render()` method, have the component render an `input` element, `button` element, and `ul` element. When the `input` element changes, it should trigger a `handleChange()` method. Also, the `input` element should render the value of `input` that's in the component's state. The `button` element should trigger a `submitMessage()` method when it's clicked.
|
||||||
|
|
||||||
|
Second, write these two methods. The `handleChange()` method should update the `input` with what the user is typing. The `submitMessage()` method should concatenate the current message (stored in `input`) to the `messages` array in local state, and clear the value of the `input`.
|
||||||
|
|
||||||
|
Finally, use the `ul` to map over the array of `messages` and render it to the screen as a list of `li` elements.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `DisplayMessages` component should initialize with a state equal to `{ input: "", messages: [] }`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
const initialState = mockedComponent.state();
|
||||||
|
return (
|
||||||
|
typeof initialState === 'object' &&
|
||||||
|
initialState.input === '' &&
|
||||||
|
initialState.messages.length === 0
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `DisplayMessages` component should render a `div` containing an `h2` element, a `button` element, a `ul` element, and `li` elements as children.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
const state = () => {
|
||||||
|
mockedComponent.setState({ messages: ['__TEST__MESSAGE'] });
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const updated = await state();
|
||||||
|
assert(
|
||||||
|
updated.find('div').length === 1 &&
|
||||||
|
updated.find('h2').length === 1 &&
|
||||||
|
updated.find('button').length === 1 &&
|
||||||
|
updated.find('ul').length === 1 &&
|
||||||
|
updated.find('li').length > 0
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`.map` should be used on the `messages` array.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(code.match(/this\.state\.messages\.map/g));
|
||||||
|
```
|
||||||
|
|
||||||
|
The `input` element should render the value of `input` in local state.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
const causeChange = (c, v) =>
|
||||||
|
c.find('input').simulate('change', { target: { value: v } });
|
||||||
|
const testValue = '__TEST__EVENT__INPUT';
|
||||||
|
const changed = () => {
|
||||||
|
causeChange(mockedComponent, testValue);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const updated = await changed();
|
||||||
|
assert(updated.find('input').props().value === testValue);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Calling the method `handleChange` should update the `input` value in state to the current input.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
const causeChange = (c, v) =>
|
||||||
|
c.find('input').simulate('change', { target: { value: v } });
|
||||||
|
const initialState = mockedComponent.state();
|
||||||
|
const testMessage = '__TEST__EVENT__MESSAGE__';
|
||||||
|
const changed = () => {
|
||||||
|
causeChange(mockedComponent, testMessage);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const afterInput = await changed();
|
||||||
|
assert(
|
||||||
|
initialState.input === '' &&
|
||||||
|
afterInput.state().input === '__TEST__EVENT__MESSAGE__'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Clicking the `Add message` button should call the method `submitMessage` which should add the current `input` to the `messages` array in state.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
const causeChange = (c, v) =>
|
||||||
|
c.find('input').simulate('change', { target: { value: v } });
|
||||||
|
const initialState = mockedComponent.state();
|
||||||
|
const testMessage_1 = '__FIRST__MESSAGE__';
|
||||||
|
const firstChange = () => {
|
||||||
|
causeChange(mockedComponent, testMessage_1);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const firstResult = await firstChange();
|
||||||
|
const firstSubmit = () => {
|
||||||
|
mockedComponent.find('button').simulate('click');
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const afterSubmit_1 = await firstSubmit();
|
||||||
|
const submitState_1 = afterSubmit_1.state();
|
||||||
|
const testMessage_2 = '__SECOND__MESSAGE__';
|
||||||
|
const secondChange = () => {
|
||||||
|
causeChange(mockedComponent, testMessage_2);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const secondResult = await secondChange();
|
||||||
|
const secondSubmit = () => {
|
||||||
|
mockedComponent.find('button').simulate('click');
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const afterSubmit_2 = await secondSubmit();
|
||||||
|
const submitState_2 = afterSubmit_2.state();
|
||||||
|
assert(
|
||||||
|
initialState.messages.length === 0 &&
|
||||||
|
submitState_1.messages.length === 1 &&
|
||||||
|
submitState_2.messages.length === 2 &&
|
||||||
|
submitState_2.messages[1] === testMessage_2
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `submitMessage` method should clear the current input.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
const causeChange = (c, v) =>
|
||||||
|
c.find('input').simulate('change', { target: { value: v } });
|
||||||
|
const initialState = mockedComponent.state();
|
||||||
|
const testMessage = '__FIRST__MESSAGE__';
|
||||||
|
const firstChange = () => {
|
||||||
|
causeChange(mockedComponent, testMessage);
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const firstResult = await firstChange();
|
||||||
|
const firstState = firstResult.state();
|
||||||
|
const firstSubmit = () => {
|
||||||
|
mockedComponent.find('button').simulate('click');
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const afterSubmit = await firstSubmit();
|
||||||
|
const submitState = afterSubmit.state();
|
||||||
|
assert(firstState.input === testMessage && submitState.input === '');
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<DisplayMessages />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class DisplayMessages extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add handleChange() and submitMessage() methods here
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
{ /* Render an input, button, and ul below this line */ }
|
||||||
|
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class DisplayMessages extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.submitMessage = this.submitMessage.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
submitMessage() {
|
||||||
|
this.setState((state) => {
|
||||||
|
const currentMessage = state.input;
|
||||||
|
return {
|
||||||
|
input: '',
|
||||||
|
messages: state.messages.concat(currentMessage)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange}/><br/>
|
||||||
|
<button onClick={this.submitMessage}>Submit</button>
|
||||||
|
<ul>
|
||||||
|
{this.state.messages.map( (message, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx}>{message}</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036146
|
||||||
|
title: Map Dispatch to Props
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301432
|
||||||
|
dashedName: map-dispatch-to-props
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The `mapDispatchToProps()` function is used to provide specific action creators to your React components so they can dispatch actions against the Redux store. It's similar in structure to the `mapStateToProps()` function you wrote in the last challenge. It returns an object that maps dispatch actions to property names, which become component `props`. However, instead of returning a piece of `state`, each property returns a function that calls `dispatch` with an action creator and any relevant action data. You have access to this `dispatch` because it's passed in to `mapDispatchToProps()` as a parameter when you define the function, just like you passed `state` to `mapStateToProps()`. Behind the scenes, React Redux is using Redux's `store.dispatch()` to conduct these dispatches with `mapDispatchToProps()`. This is similar to how it uses `store.subscribe()` for components that are mapped to `state`.
|
||||||
|
|
||||||
|
For example, you have a `loginUser()` action creator that takes a `username` as an action payload. The object returned from `mapDispatchToProps()` for this action creator would look something like:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
{
|
||||||
|
submitLoginUser: function(username) {
|
||||||
|
dispatch(loginUser(username));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor provides an action creator called `addMessage()`. Write the function `mapDispatchToProps()` that takes `dispatch` as an argument, then returns an object. The object should have a property `submitNewMessage` set to the dispatch function, which takes a parameter for the new message to add when it dispatches `addMessage()`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
`addMessage` should return an object with keys `type` and `message`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const addMessageTest = addMessage();
|
||||||
|
return (
|
||||||
|
addMessageTest.hasOwnProperty('type') &&
|
||||||
|
addMessageTest.hasOwnProperty('message')
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
`mapDispatchToProps` should be a function.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(typeof mapDispatchToProps === 'function');
|
||||||
|
```
|
||||||
|
|
||||||
|
`mapDispatchToProps` should return an object.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(typeof mapDispatchToProps() === 'object');
|
||||||
|
```
|
||||||
|
|
||||||
|
Dispatching `addMessage` with `submitNewMessage` from `mapDispatchToProps` should return a message to the dispatch function.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
let testAction;
|
||||||
|
const dispatch = (fn) => {
|
||||||
|
testAction = fn;
|
||||||
|
};
|
||||||
|
let dispatchFn = mapDispatchToProps(dispatch);
|
||||||
|
dispatchFn.submitNewMessage('__TEST__MESSAGE__');
|
||||||
|
return (
|
||||||
|
testAction.type === 'ADD' && testAction.message === '__TEST__MESSAGE__'
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: 'ADD',
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: 'ADD',
|
||||||
|
message: message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
submitNewMessage: function(message) {
|
||||||
|
dispatch(addMessage(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036145
|
||||||
|
title: Map State to Props
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301433
|
||||||
|
dashedName: map-state-to-props
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The `Provider` component allows you to provide `state` and `dispatch` to your React components, but you must specify exactly what state and actions you want. This way, you make sure that each component only has access to the state it needs. You accomplish this by creating two functions: `mapStateToProps()` and `mapDispatchToProps()`.
|
||||||
|
|
||||||
|
In these functions, you declare what pieces of state you want to have access to and which action creators you need to be able to dispatch. Once these functions are in place, you'll see how to use the React Redux `connect` method to connect them to your components in another challenge.
|
||||||
|
|
||||||
|
**Note:** Behind the scenes, React Redux uses the `store.subscribe()` method to implement `mapStateToProps()`.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Create a function `mapStateToProps()`. This function should take `state` as an argument, then return an object which maps that state to specific property names. These properties will become accessible to your component via `props`. Since this example keeps the entire state of the app in a single array, you can pass that entire state to your component. Create a property `messages` in the object that's being returned, and set it to `state`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The const `state` should be an empty array.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Array.isArray(state) && state.length === 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
`mapStateToProps` should be a function.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(typeof mapStateToProps === 'function');
|
||||||
|
```
|
||||||
|
|
||||||
|
`mapStateToProps` should return an object.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(typeof mapStateToProps() === 'object');
|
||||||
|
```
|
||||||
|
|
||||||
|
Passing an array as state to `mapStateToProps` should return this array assigned to a key of `messages`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(mapStateToProps(['messages']).messages.pop() === 'messages');
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const state = [];
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const state = [];
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
messages: state
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403614a
|
||||||
|
title: Moving Forward From Here
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301434
|
||||||
|
dashedName: moving-forward-from-here
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Congratulations! You finished the lessons on React and Redux. There's one last item worth pointing out before you move on. Typically, you won't write React apps in a code editor like this. This challenge gives you a glimpse of what the syntax looks like if you're working with npm and a file system on your own machine. The code should look similar, except for the use of `import` statements (these pull in all of the dependencies that have been provided for you in the challenges). The "Managing Packages with npm" section covers npm in more detail.
|
||||||
|
|
||||||
|
Finally, writing React and Redux code generally requires some configuration. This can get complicated quickly. If you are interested in experimenting on your own machine, the <a href="https://github.com/facebookincubator/create-react-app" target="_blank" rel="nofollow">Create React App</a> comes configured and ready to go.
|
||||||
|
|
||||||
|
Alternatively, you can enable Babel as a JavaScript Preprocessor in CodePen, add React and ReactDOM as external JavaScript resources, and work there as well.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Log the message `'Now I know React and Redux!'` to the console.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The message `Now I know React and Redux!` should be logged to the console.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(getUserInput) =>
|
||||||
|
assert(
|
||||||
|
/console\s*\.\s*log\s*\(\s*('|"|`)Now I know React and Redux!\1\s*\)/.test(
|
||||||
|
getUserInput('index')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
/*
|
||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import { Provider, connect } from 'react-redux'
|
||||||
|
import { createStore, combineReducers, applyMiddleware } from 'redux'
|
||||||
|
import thunk from 'redux-thunk'
|
||||||
|
|
||||||
|
import rootReducer from './redux/reducers'
|
||||||
|
import App from './components/App'
|
||||||
|
|
||||||
|
const store = createStore(
|
||||||
|
rootReducer,
|
||||||
|
applyMiddleware(thunk)
|
||||||
|
);
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<App/>
|
||||||
|
</Provider>,
|
||||||
|
document.getElementById('root')
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Only change code below this line
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
console.log('Now I know React and Redux!');
|
||||||
|
```
|
@ -0,0 +1,263 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036144
|
||||||
|
title: Use Provider to Connect Redux to React
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301435
|
||||||
|
dashedName: use-provider-to-connect-redux-to-react
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
In the last challenge, you created a Redux store to handle the messages array and created an action for adding new messages. The next step is to provide React access to the Redux store and the actions it needs to dispatch updates. React Redux provides its `react-redux` package to help accomplish these tasks.
|
||||||
|
|
||||||
|
React Redux provides a small API with two key features: `Provider` and `connect`. Another challenge covers `connect`. The `Provider` is a wrapper component from React Redux that wraps your React app. This wrapper then allows you to access the Redux `store` and `dispatch` functions throughout your component tree. `Provider` takes two props, the Redux store and the child components of your app. Defining the `Provider` for an App component might look like this:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<Provider store={store}>
|
||||||
|
<App/>
|
||||||
|
</Provider>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor now shows all your Redux and React code from the past several challenges. It includes the Redux store, actions, and the `DisplayMessages` component. The only new piece is the `AppWrapper` component at the bottom. Use this top level component to render the `Provider` from `ReactRedux`, and pass the Redux store as a prop. Then render the `DisplayMessages` component as a child. Once you are finished, you should see your React component rendered to the page.
|
||||||
|
|
||||||
|
**Note:** React Redux is available as a global variable here, so you can access the Provider with dot notation. The code in the editor takes advantage of this and sets it to a constant `Provider` for you to use in the `AppWrapper` render method.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `AppWrapper` should render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return mockedComponent.find('AppWrapper').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Provider` wrapper component should have a prop of `store` passed to it, equal to the Redux store.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(getUserInput) =>
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return __helpers
|
||||||
|
.removeWhiteSpace(getUserInput('index'))
|
||||||
|
.includes('<Providerstore={store}>');
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
`DisplayMessages` should render as a child of `AppWrapper`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('AppWrapper').find('DisplayMessages').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `DisplayMessages` component should render an `h2`, `input`, `button`, and `ul` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('div').length === 1 &&
|
||||||
|
mockedComponent.find('h2').length === 1 &&
|
||||||
|
mockedComponent.find('button').length === 1 &&
|
||||||
|
mockedComponent.find('ul').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Redux:
|
||||||
|
const ADD = 'ADD';
|
||||||
|
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: ADD,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageReducer = (state = [], action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
action.message
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const store = Redux.createStore(messageReducer);
|
||||||
|
|
||||||
|
// React:
|
||||||
|
|
||||||
|
class DisplayMessages extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.submitMessage = this.submitMessage.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
submitMessage() {
|
||||||
|
this.setState((state) => {
|
||||||
|
const currentMessage = state.input;
|
||||||
|
return {
|
||||||
|
input: '',
|
||||||
|
messages: state.messages.concat(currentMessage)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange}/><br/>
|
||||||
|
<button onClick={this.submitMessage}>Submit</button>
|
||||||
|
<ul>
|
||||||
|
{this.state.messages.map( (message, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx}>{message}</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Provider = ReactRedux.Provider;
|
||||||
|
|
||||||
|
class AppWrapper extends React.Component {
|
||||||
|
// Render the Provider below this line
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Redux:
|
||||||
|
const ADD = 'ADD';
|
||||||
|
|
||||||
|
const addMessage = (message) => {
|
||||||
|
return {
|
||||||
|
type: ADD,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageReducer = (state = [], action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
action.message
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = Redux.createStore(messageReducer);
|
||||||
|
|
||||||
|
// React:
|
||||||
|
|
||||||
|
class DisplayMessages extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.submitMessage = this.submitMessage.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
submitMessage() {
|
||||||
|
this.setState((state) => {
|
||||||
|
const currentMessage = state.input;
|
||||||
|
return {
|
||||||
|
input: '',
|
||||||
|
messages: state.messages.concat(currentMessage)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Type in a new Message:</h2>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange}/><br/>
|
||||||
|
<button onClick={this.submitMessage}>Submit</button>
|
||||||
|
<ul>
|
||||||
|
{this.state.messages.map( (message, idx) => {
|
||||||
|
return (
|
||||||
|
<li key={idx}>{message}</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Provider = ReactRedux.Provider;
|
||||||
|
|
||||||
|
class AppWrapper extends React.Component {
|
||||||
|
// Change code below this line
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Provider store = {store}>
|
||||||
|
<DisplayMessages/>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Change code above this line
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,165 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403616e
|
||||||
|
title: Access Props Using this.props
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301375
|
||||||
|
dashedName: access-props-using-this-props
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The last several challenges covered the basic ways to pass props to child components. But what if the child component that you're passing a prop to is an ES6 class component, rather than a stateless functional component? The ES6 class component uses a slightly different convention to access props.
|
||||||
|
|
||||||
|
Anytime you refer to a class component within itself, you use the `this` keyword. To access props within a class component, you preface the code that you use to access it with `this`. For example, if an ES6 class component has a prop called `data`, you write `{this.props.data}` in JSX.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Render an instance of the `ReturnTempPassword` component in the parent component `ResetPassword`. Here, give `ReturnTempPassword` a prop of `tempPassword` and assign it a value of a string that is at least 8 characters long. Within the child, `ReturnTempPassword`, access the `tempPassword` prop within the `strong` tags to make sure the user sees the temporary password.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `ResetPassword` component should return a single `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ResetPassword));
|
||||||
|
return mockedComponent.children().type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The fourth child of `ResetPassword` should be the `ReturnTempPassword` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ResetPassword));
|
||||||
|
return (
|
||||||
|
mockedComponent.children().childAt(3).name() === 'ReturnTempPassword'
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ReturnTempPassword` component should have a prop called `tempPassword`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ResetPassword));
|
||||||
|
return mockedComponent.find('ReturnTempPassword').props().tempPassword;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `tempPassword` prop of `ReturnTempPassword` should be equal to a string of at least 8 characters.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ResetPassword));
|
||||||
|
const temp = mockedComponent.find('ReturnTempPassword').props()
|
||||||
|
.tempPassword;
|
||||||
|
return typeof temp === 'string' && temp.length >= 8;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ReturnTempPassword` component should display the password you create as the `tempPassword` prop within `strong` tags.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ResetPassword));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('strong').text() ===
|
||||||
|
mockedComponent.find('ReturnTempPassword').props().tempPassword
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<ResetPassword />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class ReturnTempPassword extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<p>Your temporary password is: <strong></strong></p>
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ResetPassword extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Reset Password</h2>
|
||||||
|
<h3>We've generated a new temporary password for you.</h3>
|
||||||
|
<h3>Please reset this password from your account settings ASAP.</h3>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class ReturnTempPassword extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Your temporary password is: <strong>{this.props.tempPassword}</strong></p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ResetPassword extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Reset Password</h2>
|
||||||
|
<h3>We've generated a new temporary password for you.</h3>
|
||||||
|
<h3>Please reset this password from your account settings ASAP.</h3>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<ReturnTempPassword tempPassword="serrPbqrPnzc" />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
id: 5a24bbe0dba28a8d3cbd4c5e
|
||||||
|
title: Add Comments in JSX
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301376
|
||||||
|
dashedName: add-comments-in-jsx
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
JSX is a syntax that gets compiled into valid JavaScript. Sometimes, for readability, you might need to add comments to your code. Like most programming languages, JSX has its own way to do this.
|
||||||
|
|
||||||
|
To put comments inside JSX, you use the syntax `{/* */}` to wrap around the comment text.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has a JSX element similar to what you created in the last challenge. Add a comment somewhere within the provided `div` element, without modifying the existing `h1` or `p` elements.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The constant `JSX` should return a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.type === 'div');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should contain an `h1` tag as the first element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.props.children[0].type === 'h1');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should contain a `p` tag as the second element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.props.children[1].type === 'p');
|
||||||
|
```
|
||||||
|
|
||||||
|
The existing `h1` and `p` elements should not be modified.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
JSX.props.children[0].props.children === 'This is a block of JSX' &&
|
||||||
|
JSX.props.children[1].props.children === "Here's a subtitle"
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `JSX` should use valid comment syntax.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(/<div>[\s\S]*{\s*\/\*[\s\S]*\*\/\s*}[\s\S]*<\/div>/.test(code));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(JSX, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = (
|
||||||
|
<div>
|
||||||
|
<h1>This is a block of JSX</h1>
|
||||||
|
<p>Here's a subtitle</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = (
|
||||||
|
<div>
|
||||||
|
<h1>This is a block of JSX</h1>
|
||||||
|
{ /* this is a JSX comment */ }
|
||||||
|
<p>Here's a subtitle</p>
|
||||||
|
</div>);
|
||||||
|
```
|
@ -0,0 +1,179 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403617e
|
||||||
|
title: Add Event Listeners
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301377
|
||||||
|
dashedName: add-event-listeners
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The `componentDidMount()` method is also the best place to attach any event listeners you need to add for specific functionality. React provides a synthetic event system which wraps the native event system present in browsers. This means that the synthetic event system behaves exactly the same regardless of the user's browser - even if the native events may behave differently between different browsers.
|
||||||
|
|
||||||
|
You've already been using some of these synthetic event handlers such as `onClick()`. React's synthetic event system is great to use for most interactions you'll manage on DOM elements. However, if you want to attach an event handler to the document or window objects, you have to do this directly.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Attach an event listener in the `componentDidMount()` method for `keydown` events and have these events trigger the callback `handleKeyPress()`. You can use `document.addEventListener()` which takes the event (in quotes) as the first argument and the callback as the second argument.
|
||||||
|
|
||||||
|
Then, in `componentWillUnmount()`, remove this same event listener. You can pass the same arguments to `document.removeEventListener()`. It's good practice to use this lifecycle method to do any clean up on React components before they are unmounted and destroyed. Removing event listeners is an example of one such clean up action.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
`MyComponent` should render a `div` element which wraps an `h1` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
return mockedComponent.find('div').children().find('h1').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
A `keydown` listener should be attached to the document in `componentDidMount`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
const didMountString = mockedComponent
|
||||||
|
.instance()
|
||||||
|
.componentDidMount.toString();
|
||||||
|
return new RegExp(
|
||||||
|
'document.addEventListener(.|\n|\r)+keydown(.|\n|\r)+this.handleKeyPress'
|
||||||
|
).test(didMountString);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `keydown` listener should be removed from the document in `componentWillUnmount`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
const willUnmountString = mockedComponent
|
||||||
|
.instance()
|
||||||
|
.componentWillUnmount.toString();
|
||||||
|
return new RegExp(
|
||||||
|
'document.removeEventListener(.|\n|\r)+keydown(.|\n|\r)+this.handleKeyPress'
|
||||||
|
).test(willUnmountString);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Once the component has mounted, pressing `enter` should update its state and the rendered `h1` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
const beforeState = mockedComponent.state('message');
|
||||||
|
const beforeText = mockedComponent.find('h1').text();
|
||||||
|
const pressEnterKey = () => {
|
||||||
|
mockedComponent.instance().handleKeyPress({ keyCode: 13 });
|
||||||
|
return waitForIt(() => {
|
||||||
|
mockedComponent.update();
|
||||||
|
return {
|
||||||
|
state: mockedComponent.state('message'),
|
||||||
|
text: mockedComponent.find('h1').text()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const afterKeyPress = await pressEnterKey();
|
||||||
|
assert(
|
||||||
|
beforeState !== afterKeyPress.state && beforeText !== afterKeyPress.text
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<MyComponent />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
message: ''
|
||||||
|
};
|
||||||
|
this.handleEnter = this.handleEnter.bind(this);
|
||||||
|
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||||
|
}
|
||||||
|
// Change code below this line
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
|
||||||
|
}
|
||||||
|
// Change code above this line
|
||||||
|
handleEnter() {
|
||||||
|
this.setState((state) => ({
|
||||||
|
message: state.message + 'You pressed the enter key! '
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
handleKeyPress(event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
this.handleEnter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{this.state.message}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
message: ''
|
||||||
|
};
|
||||||
|
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||||
|
this.handleEnter = this.handleEnter.bind(this); }
|
||||||
|
componentDidMount() {
|
||||||
|
// Change code below this line
|
||||||
|
document.addEventListener('keydown', this.handleKeyPress);
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
// Change code below this line
|
||||||
|
document.removeEventListener('keydown', this.handleKeyPress);
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
handleEnter() {
|
||||||
|
this.setState((state) => ({
|
||||||
|
message: state.message + 'You pressed the enter key! '
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
handleKeyPress(event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
this.handleEnter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{this.state.message}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036182
|
||||||
|
title: Add Inline Styles in React
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301378
|
||||||
|
dashedName: add-inline-styles-in-react
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You may have noticed in the last challenge that there were several other syntax differences from HTML inline styles in addition to the `style` attribute set to a JavaScript object. First, the names of certain CSS style properties use camel case. For example, the last challenge set the size of the font with `fontSize` instead of `font-size`. Hyphenated words like `font-size` are invalid syntax for JavaScript object properties, so React uses camel case. As a rule, any hyphenated style properties are written using camel case in JSX.
|
||||||
|
|
||||||
|
All property value length units (like `height`, `width`, and `fontSize`) are assumed to be in `px` unless otherwise specified. If you want to use `em`, for example, you wrap the value and the units in quotes, like `{fontSize: "4em"}`. Other than the length values that default to `px`, all other property values should be wrapped in quotes.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
If you have a large set of styles, you can assign a style `object` to a constant to keep your code organized. Declare your styles constant as a global variable at the top of the file. Initialize `styles` constant and assign an `object` with three style properties and their values to it. Give the `div` a color of `purple`, a font-size of `40`, and a border of `2px solid purple`. Then set the `style` attribute equal to the `styles` constant.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `styles` variable should be an `object` with three properties.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Object.keys(styles).length === 3);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `styles` variable should have a `color` property set to a value of `purple`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(styles.color === 'purple');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `styles` variable should have a `fontSize` property set to a value of `40`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(styles.fontSize === 40);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `styles` variable should have a `border` property set to a value of `2px solid purple`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(styles.border === '2px solid purple');
|
||||||
|
```
|
||||||
|
|
||||||
|
The component should render a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.shallow(React.createElement(Colorful));
|
||||||
|
return mockedComponent.type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` element should have its styles defined by the `styles` object.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.shallow(React.createElement(Colorful));
|
||||||
|
return (
|
||||||
|
mockedComponent.props().style.color === 'purple' &&
|
||||||
|
mockedComponent.props().style.fontSize === 40 &&
|
||||||
|
mockedComponent.props().style.border === '2px solid purple'
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<Colorful />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// Change code above this line
|
||||||
|
class Colorful extends React.Component {
|
||||||
|
render() {
|
||||||
|
// Change code below this line
|
||||||
|
return (
|
||||||
|
<div style={{color: "yellow", fontSize: 24}}>Style Me!</div>
|
||||||
|
);
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const styles = {
|
||||||
|
color: "purple",
|
||||||
|
fontSize: 40,
|
||||||
|
border: "2px solid purple"
|
||||||
|
};
|
||||||
|
// Change code above this line
|
||||||
|
class Colorful extends React.Component {
|
||||||
|
render() {
|
||||||
|
// Change code below this line
|
||||||
|
return (
|
||||||
|
<div style={styles}>Style Me!</div>
|
||||||
|
);
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,136 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036174
|
||||||
|
title: Bind 'this' to a Class Method
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301379
|
||||||
|
dashedName: bind-this-to-a-class-method
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
In addition to setting and updating `state`, you can also define methods for your component class. A class method typically needs to use the `this` keyword so it can access properties on the class (such as `state` and `props`) inside the scope of the method. There are a few ways to allow your class methods to access `this`.
|
||||||
|
|
||||||
|
One common way is to explicitly bind `this` in the constructor so `this` becomes bound to the class methods when the component is initialized. You may have noticed the last challenge used `this.handleClick = this.handleClick.bind(this)` for its `handleClick` method in the constructor. Then, when you call a function like `this.setState()` within your class method, `this` refers to the class and will not be `undefined`.
|
||||||
|
|
||||||
|
**Note:** The `this` keyword is one of the most confusing aspects of JavaScript but it plays an important role in React. Although its behavior here is totally normal, these lessons aren't the place for an in-depth review of `this` so please refer to other lessons if the above is confusing!
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has a component with a `state` that keeps track of the text. It also has a method which allows you to set the text to `You clicked!`. However, the method doesn't work because it's using the `this` keyword that is undefined. Fix it by explicitly binding `this` to the `handleClick()` method in the component's constructor.
|
||||||
|
|
||||||
|
Next, add a click handler to the `button` element in the render method. It should trigger the `handleClick()` method when the button receives a click event. Remember that the method you pass to the `onClick` handler needs curly braces because it should be interpreted directly as JavaScript.
|
||||||
|
|
||||||
|
Once you complete the above steps you should be able to click the button and see `You clicked!`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
`MyComponent` should return a `div` element which wraps two elements, a button and an `h1` element, in that order.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
Enzyme.mount(React.createElement(MyComponent)).find('div').length === 1 &&
|
||||||
|
Enzyme.mount(React.createElement(MyComponent))
|
||||||
|
.find('div')
|
||||||
|
.childAt(0)
|
||||||
|
.type() === 'button' &&
|
||||||
|
Enzyme.mount(React.createElement(MyComponent))
|
||||||
|
.find('div')
|
||||||
|
.childAt(1)
|
||||||
|
.type() === 'h1'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The state of `MyComponent` should initialize with the key value pair `{ text: "Hello" }`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
Enzyme.mount(React.createElement(MyComponent)).state('text') === 'Hello'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Clicking the `button` element should run the `handleClick` method and set the state `text` to `You clicked!`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
const first = () => {
|
||||||
|
mockedComponent.setState({ text: 'Hello' });
|
||||||
|
return waitForIt(() => mockedComponent.state('text'));
|
||||||
|
};
|
||||||
|
const second = () => {
|
||||||
|
mockedComponent.find('button').simulate('click');
|
||||||
|
return waitForIt(() => mockedComponent.state('text'));
|
||||||
|
};
|
||||||
|
const firstValue = await first();
|
||||||
|
const secondValue = await second();
|
||||||
|
assert(firstValue === 'Hello' && secondValue === 'You clicked!');
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<MyComponent />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
text: "Hello"
|
||||||
|
};
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
handleClick() {
|
||||||
|
this.setState({
|
||||||
|
text: "You clicked!"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<button>Click Me</button>
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
<h1>{this.state.text}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
text: "Hello"
|
||||||
|
};
|
||||||
|
this.handleClick = this.handleClick.bind(this);
|
||||||
|
}
|
||||||
|
handleClick() {
|
||||||
|
this.setState({
|
||||||
|
text: "You clicked!"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button onClick = {this.handleClick}>Click Me</button>
|
||||||
|
<h1>{this.state.text}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,176 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036189
|
||||||
|
title: Change Inline CSS Conditionally Based on Component State
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301380
|
||||||
|
dashedName: change-inline-css-conditionally-based-on-component-state
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
At this point, you've seen several applications of conditional rendering and the use of inline styles. Here's one more example that combines both of these topics. You can also render CSS conditionally based on the state of a React component. To do this, you check for a condition, and if that condition is met, you modify the styles object that's assigned to the JSX elements in the render method.
|
||||||
|
|
||||||
|
This paradigm is important to understand because it is a dramatic shift from the more traditional approach of applying styles by modifying DOM elements directly (which is very common with jQuery, for example). In that approach, you must keep track of when elements change and also handle the actual manipulation directly. It can become difficult to keep track of changes, potentially making your UI unpredictable. When you set a style object based on a condition, you describe how the UI should look as a function of the application's state. There is a clear flow of information that only moves in one direction. This is the preferred method when writing applications with React.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has a simple controlled input component with a styled border. You want to style this border red if the user types more than 15 characters of text in the input box. Add a condition to check for this and, if the condition is valid, set the input border style to `3px solid red`. You can try it out by entering text in the input.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `GateKeeper` component should render a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(GateKeeper));
|
||||||
|
return mockedComponent.find('div').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `GateKeeper` component should be initialized with a state key `input` set to an empty string.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(GateKeeper));
|
||||||
|
return mockedComponent.state().input === '';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `GateKeeper` component should render an `h3` tag and an `input` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(GateKeeper));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('h3').length === 1 &&
|
||||||
|
mockedComponent.find('input').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `input` tag should initially have a style of `1px solid black` for the `border` property.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(GateKeeper));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('input').props().style.border === '1px solid black'
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `input` tag should be styled with a border of `3px solid red` if the input value in state is longer than 15 characters.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(GateKeeper));
|
||||||
|
const simulateChange = (el, value) =>
|
||||||
|
el.simulate('change', { target: { value } });
|
||||||
|
let initialStyle = mockedComponent.find('input').props().style.border;
|
||||||
|
const state_1 = () => {
|
||||||
|
mockedComponent.setState({ input: 'this is 15 char' });
|
||||||
|
return waitForIt(() => mockedComponent.find('input').props().style.border);
|
||||||
|
};
|
||||||
|
const state_2 = () => {
|
||||||
|
mockedComponent.setState({
|
||||||
|
input: 'A very long string longer than 15 characters.'
|
||||||
|
});
|
||||||
|
return waitForIt(() => mockedComponent.find('input').props().style.border);
|
||||||
|
};
|
||||||
|
const style_1 = await state_1();
|
||||||
|
const style_2 = await state_2();
|
||||||
|
assert(
|
||||||
|
initialStyle === '1px solid black' &&
|
||||||
|
style_1 === '1px solid black' &&
|
||||||
|
style_2 === '3px solid red'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<GateKeeper />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class GateKeeper extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: ''
|
||||||
|
};
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({ input: event.target.value })
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
let inputStyle = {
|
||||||
|
border: '1px solid black'
|
||||||
|
};
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Don't Type Too Much:</h3>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
style={inputStyle}
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class GateKeeper extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: ''
|
||||||
|
};
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({ input: event.target.value })
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
let inputStyle = {
|
||||||
|
border: '1px solid black'
|
||||||
|
};
|
||||||
|
if (this.state.input.length > 15) {
|
||||||
|
inputStyle.border = '3px solid red';
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Don't Type Too Much:</h3>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
style={inputStyle}
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,199 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036166
|
||||||
|
title: Compose React Components
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301381
|
||||||
|
dashedName: compose-react-components
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
As the challenges continue to use more complex compositions with React components and JSX, there is one important point to note. Rendering ES6 style class components within other components is no different than rendering the simple components you used in the last few challenges. You can render JSX elements, stateless functional components, and ES6 class components within other components.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
In the code editor, the `TypesOfFood` component is already rendering a component called `Vegetables`. Also, there is the `Fruits` component from the last challenge.
|
||||||
|
|
||||||
|
Nest two components inside of `Fruits` — first `NonCitrus`, and then `Citrus`. Both of these components are provided for you behind the scenes. Next, nest the `Fruits` class component into the `TypesOfFood` component, below the `h1` header and above `Vegetables`. The result should be a series of nested components, which uses two different component types.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `TypesOfFood` component should return a single `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
|
||||||
|
return mockedComponent.children().type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `TypesOfFood` component should return the `Fruits` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
|
||||||
|
return mockedComponent.children().childAt(1).name() === 'Fruits';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Fruits` component should return the `NonCitrus` component and the `Citrus` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('Fruits').children().find('NonCitrus').length ===
|
||||||
|
1 &&
|
||||||
|
mockedComponent.find('Fruits').children().find('Citrus').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `TypesOfFood` component should return the `Vegetables` component below the `Fruits` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
|
||||||
|
return mockedComponent.children().childAt(2).name() === 'Vegetables';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --before-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class NonCitrus extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4>Non-Citrus:</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Apples</li>
|
||||||
|
<li>Blueberries</li>
|
||||||
|
<li>Strawberries</li>
|
||||||
|
<li>Bananas</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class Citrus extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4>Citrus:</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Lemon</li>
|
||||||
|
<li>Lime</li>
|
||||||
|
<li>Orange</li>
|
||||||
|
<li>Grapefruit</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class Vegetables extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Vegetables:</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Brussel Sprouts</li>
|
||||||
|
<li>Broccoli</li>
|
||||||
|
<li>Squash</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<TypesOfFood />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class Fruits extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Fruits:</h2>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TypesOfFood extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Types of Food:</h1>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
<Vegetables />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class Fruits extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Fruits:</h2>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<NonCitrus />
|
||||||
|
<Citrus />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypesOfFood extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Types of Food:</h1>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<Fruits />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
<Vegetables />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,110 @@
|
|||||||
|
---
|
||||||
|
id: 5a24bbe0dba28a8d3cbd4c5d
|
||||||
|
title: Create a Complex JSX Element
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301382
|
||||||
|
dashedName: create-a-complex-jsx-element
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The last challenge was a simple example of JSX, but JSX can represent more complex HTML as well.
|
||||||
|
|
||||||
|
One important thing to know about nested JSX is that it must return a single element.
|
||||||
|
|
||||||
|
This one parent element would wrap all of the other levels of nested elements.
|
||||||
|
|
||||||
|
For instance, several JSX elements written as siblings with no parent wrapper element will not transpile.
|
||||||
|
|
||||||
|
Here's an example:
|
||||||
|
|
||||||
|
**Valid JSX:**
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<div>
|
||||||
|
<p>Paragraph One</p>
|
||||||
|
<p>Paragraph Two</p>
|
||||||
|
<p>Paragraph Three</p>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Invalid JSX:**
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<p>Paragraph One</p>
|
||||||
|
<p>Paragraph Two</p>
|
||||||
|
<p>Paragraph Three</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Define a new constant `JSX` that renders a `div` which contains the following elements in order:
|
||||||
|
|
||||||
|
An `h1`, a `p`, and an unordered list that contains three `li` items. You can include any text you want within each element.
|
||||||
|
|
||||||
|
**Note:** When rendering multiple elements like this, you can wrap them all in parentheses, but it's not strictly required. Also notice this challenge uses a `div` tag to wrap all the child elements within a single parent element. If you remove the `div`, the JSX will no longer transpile. Keep this in mind, since it will also apply when you return JSX elements in React components.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The constant `JSX` should return a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.type === 'div');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should contain an `h1` tag as the first element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.props.children[0].type === 'h1');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should contain a `p` tag as the second element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.props.children[1].type === 'p');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should contain a `ul` tag as the third element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.props.children[2].type === 'ul');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ul` should contain three `li` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
JSX.props.children
|
||||||
|
.filter((ele) => ele.type === 'ul')[0]
|
||||||
|
.props.children.filter((ele) => ele.type === 'li').length === 3
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(JSX, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = (
|
||||||
|
<div>
|
||||||
|
<h1>Hello JSX!</h1>
|
||||||
|
<p>Some info</p>
|
||||||
|
<ul>
|
||||||
|
<li>An item</li>
|
||||||
|
<li>Another item</li>
|
||||||
|
<li>A third item</li>
|
||||||
|
</ul>
|
||||||
|
</div>);
|
||||||
|
```
|
@ -0,0 +1,134 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036164
|
||||||
|
title: Create a Component with Composition
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301383
|
||||||
|
dashedName: create-a-component-with-composition
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now we will look at how we can compose multiple React components together. Imagine you are building an app and have created three components: a `Navbar`, `Dashboard`, and `Footer`.
|
||||||
|
|
||||||
|
To compose these components together, you could create an `App` *parent* component which renders each of these three components as *children*. To render a component as a child in a React component, you include the component name written as a custom HTML tag in the JSX. For example, in the `render` method you could write:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
return (
|
||||||
|
<App>
|
||||||
|
<Navbar />
|
||||||
|
<Dashboard />
|
||||||
|
<Footer />
|
||||||
|
</App>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
When React encounters a custom HTML tag that references another component (a component name wrapped in `< />` like in this example), it renders the markup for that component in the location of the tag. This should illustrate the parent/child relationship between the `App` component and the `Navbar`, `Dashboard`, and `Footer`.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
In the code editor, there is a simple functional component called `ChildComponent` and a class component called `ParentComponent`. Compose the two together by rendering the `ChildComponent` within the `ParentComponent`. Make sure to close the `ChildComponent` tag with a forward slash.
|
||||||
|
|
||||||
|
**Note:** `ChildComponent` is defined with an ES6 arrow function because this is a very common practice when using React. However, know that this is just a function. If you aren't familiar with the arrow function syntax, please refer to the JavaScript section.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The React component should return a single `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
var shallowRender = Enzyme.shallow(React.createElement(ParentComponent));
|
||||||
|
return shallowRender.type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The component should return two nested elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
var shallowRender = Enzyme.shallow(React.createElement(ParentComponent));
|
||||||
|
return shallowRender.children().length === 2;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The component should return the `ChildComponent` as its second child.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ParentComponent));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('ParentComponent').find('ChildComponent').length ===
|
||||||
|
1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<ParentComponent />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const ChildComponent = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>I am the child</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ParentComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>I am the parent</h1>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
|
||||||
|
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const ChildComponent = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>I am the child</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ParentComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>I am the parent</h1>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<ChildComponent />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,209 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036179
|
||||||
|
title: Create a Controlled Form
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301384
|
||||||
|
dashedName: create-a-controlled-form
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The last challenge showed that React can control the internal state for certain elements like `input` and `textarea`, which makes them controlled components. This applies to other form elements as well, including the regular HTML `form` element.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The `MyForm` component is set up with an empty `form` with a submit handler. The submit handler will be called when the form is submitted.
|
||||||
|
|
||||||
|
We've added a button which submits the form. You can see it has the `type` set to `submit` indicating it is the button controlling the form. Add the `input` element in the `form` and set its `value` and `onChange()` attributes like the last challenge. You should then complete the `handleSubmit` method so that it sets the component state property `submit` to the current input value in the local `state`.
|
||||||
|
|
||||||
|
**Note:** You also must call `event.preventDefault()` in the submit handler, to prevent the default form submit behavior which will refresh the web page.
|
||||||
|
|
||||||
|
Finally, create an `h1` tag after the `form` which renders the `submit` value from the component's `state`. You can then type in the form and click the button (or press enter), and you should see your input rendered to the page.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
`MyForm` should return a `div` element which contains a `form` and an `h1` tag. The form should include an `input` and a `button`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyForm));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('div').children().find('form').length === 1 &&
|
||||||
|
mockedComponent.find('div').children().find('h1').length === 1 &&
|
||||||
|
mockedComponent.find('form').children().find('input').length === 1 &&
|
||||||
|
mockedComponent.find('form').children().find('button').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The state of `MyForm` should initialize with `input` and `submit` properties, both set to empty strings.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
Enzyme.mount(React.createElement(MyForm)).state('input') === '' &&
|
||||||
|
Enzyme.mount(React.createElement(MyForm)).state('submit') === ''
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Typing in the `input` element should update the `input` property of the component's state.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyForm));
|
||||||
|
const _1 = () => {
|
||||||
|
mockedComponent.setState({ input: '' });
|
||||||
|
return mockedComponent.state('input');
|
||||||
|
};
|
||||||
|
const _2 = () => {
|
||||||
|
mockedComponent
|
||||||
|
.find('input')
|
||||||
|
.simulate('change', { target: { value: 'TestInput' } });
|
||||||
|
return {
|
||||||
|
state: mockedComponent.state('input'),
|
||||||
|
inputVal: mockedComponent.find('input').props().value
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const before = _1();
|
||||||
|
const after = _2();
|
||||||
|
assert(
|
||||||
|
before === '' &&
|
||||||
|
after.state === 'TestInput' &&
|
||||||
|
after.inputVal === 'TestInput'
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
Submitting the form should run `handleSubmit` which should set the `submit` property in state equal to the current input.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyForm));
|
||||||
|
const _1 = () => {
|
||||||
|
mockedComponent.setState({ input: '' });
|
||||||
|
mockedComponent.setState({ submit: '' });
|
||||||
|
mockedComponent
|
||||||
|
.find('input')
|
||||||
|
.simulate('change', { target: { value: 'SubmitInput' } });
|
||||||
|
return mockedComponent.state('submit');
|
||||||
|
};
|
||||||
|
const _2 = () => {
|
||||||
|
mockedComponent.find('form').simulate('submit');
|
||||||
|
return mockedComponent.state('submit');
|
||||||
|
};
|
||||||
|
const before = _1();
|
||||||
|
const after = _2();
|
||||||
|
assert(before === '' && after === 'SubmitInput');
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
The `h1` header should render the value of the `submit` field from the component's state.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyForm));
|
||||||
|
const _1 = () => {
|
||||||
|
mockedComponent.setState({ input: '' });
|
||||||
|
mockedComponent.setState({ submit: '' });
|
||||||
|
mockedComponent
|
||||||
|
.find('input')
|
||||||
|
.simulate('change', { target: { value: 'TestInput' } });
|
||||||
|
return mockedComponent.find('h1').text();
|
||||||
|
};
|
||||||
|
const _2 = () => {
|
||||||
|
mockedComponent.find('form').simulate('submit');
|
||||||
|
return mockedComponent.find('h1').text();
|
||||||
|
};
|
||||||
|
const before = _1();
|
||||||
|
const after = _2();
|
||||||
|
assert(before === '' && after === 'TestInput');
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<MyForm />, document.getElementById('root'));
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyForm extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
submit: ''
|
||||||
|
};
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
handleSubmit(event) {
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
{/* Change code below this line */}
|
||||||
|
|
||||||
|
{/* Change code above this line */}
|
||||||
|
<button type='submit'>Submit!</button>
|
||||||
|
</form>
|
||||||
|
{/* Change code below this line */}
|
||||||
|
|
||||||
|
{/* Change code above this line */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyForm extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: '',
|
||||||
|
submit: ''
|
||||||
|
};
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
handleSubmit(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.setState(state => ({
|
||||||
|
submit: state.input
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<form onSubmit={this.handleSubmit}>
|
||||||
|
<input value={this.state.input} onChange={this.handleChange} />
|
||||||
|
<button type='submit'>Submit!</button>
|
||||||
|
</form>
|
||||||
|
<h1>{this.state.submit}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036178
|
||||||
|
title: Create a Controlled Input
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301385
|
||||||
|
dashedName: create-a-controlled-input
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Your application may have more complex interactions between `state` and the rendered UI. For example, form control elements for text input, such as `input` and `textarea`, maintain their own state in the DOM as the user types. With React, you can move this mutable state into a React component's `state`. The user's input becomes part of the application `state`, so React controls the value of that input field. Typically, if you have React components with input fields the user can type into, it will be a controlled input form.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has the skeleton of a component called `ControlledInput` to create a controlled `input` element. The component's `state` is already initialized with an `input` property that holds an empty string. This value represents the text a user types into the `input` field.
|
||||||
|
|
||||||
|
First, create a method called `handleChange()` that has a parameter called `event`. When the method is called, it receives an `event` object that contains a string of text from the `input` element. You can access this string with `event.target.value` inside the method. Update the `input` property of the component's `state` with this new string.
|
||||||
|
|
||||||
|
In the `render` method, create the `input` element above the `h4` tag. Add a `value` attribute which is equal to the `input` property of the component's `state`. Then add an `onChange()` event handler set to the `handleChange()` method.
|
||||||
|
|
||||||
|
When you type in the input box, that text is processed by the `handleChange()` method, set as the `input` property in the local `state`, and rendered as the value in the `input` box on the page. The component `state` is the single source of truth regarding the input data.
|
||||||
|
|
||||||
|
Last but not least, don't forget to add the necessary bindings in the constructor.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
`ControlledInput` should return a `div` element which contains an `input` and a `p` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
Enzyme.mount(React.createElement(ControlledInput))
|
||||||
|
.find('div')
|
||||||
|
.children()
|
||||||
|
.find('input').length === 1 &&
|
||||||
|
Enzyme.mount(React.createElement(ControlledInput))
|
||||||
|
.find('div')
|
||||||
|
.children()
|
||||||
|
.find('p').length === 1
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The state of `ControlledInput` should initialize with an `input` property set to an empty string.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.strictEqual(
|
||||||
|
Enzyme.mount(React.createElement(ControlledInput)).state('input'),
|
||||||
|
''
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Typing in the input element should update the state and the value of the input, and the `p` element should render this state as you type.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ControlledInput));
|
||||||
|
const _1 = () => {
|
||||||
|
mockedComponent.setState({ input: '' });
|
||||||
|
return waitForIt(() => mockedComponent.state('input'));
|
||||||
|
};
|
||||||
|
const _2 = () => {
|
||||||
|
mockedComponent
|
||||||
|
.find('input')
|
||||||
|
.simulate('change', { target: { value: 'TestInput' } });
|
||||||
|
return waitForIt(() => ({
|
||||||
|
state: mockedComponent.state('input'),
|
||||||
|
text: mockedComponent.find('p').text(),
|
||||||
|
inputVal: mockedComponent.find('input').props().value
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
const before = await _1();
|
||||||
|
const after = await _2();
|
||||||
|
assert(
|
||||||
|
before === '' &&
|
||||||
|
after.state === 'TestInput' &&
|
||||||
|
after.text === 'TestInput' &&
|
||||||
|
after.inputVal === 'TestInput'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<ControlledInput />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class ControlledInput extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: ''
|
||||||
|
};
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ /* Change code below this line */}
|
||||||
|
|
||||||
|
{ /* Change code above this line */}
|
||||||
|
<h4>Controlled Input:</h4>
|
||||||
|
<p>{this.state.input}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class ControlledInput extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
input: ''
|
||||||
|
};
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
input: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
value={this.state.input}
|
||||||
|
onChange={this.handleChange} />
|
||||||
|
<h4>Controlled Input:</h4>
|
||||||
|
|
||||||
|
<p>{this.state.input}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036163
|
||||||
|
title: Create a React Component
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301386
|
||||||
|
dashedName: create-a-react-component
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The other way to define a React component is with the ES6 `class` syntax. In the following example, `Kitten` extends `React.Component`:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class Kitten extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<h1>Hi</h1>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates an ES6 class `Kitten` which extends the `React.Component` class. So the `Kitten` class now has access to many useful React features, such as local state and lifecycle hooks. Don't worry if you aren't familiar with these terms yet, they will be covered in greater detail in later challenges. Also notice the `Kitten` class has a `constructor` defined within it that calls `super()`. It uses `super()` to call the constructor of the parent class, in this case `React.Component`. The constructor is a special method used during the initialization of objects that are created with the `class` keyword. It is best practice to call a component's `constructor` with `super`, and pass `props` to both. This makes sure the component is initialized properly. For now, know that it is standard for this code to be included. Soon you will see other uses for the constructor as well as `props`.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
`MyComponent` is defined in the code editor using class syntax. Finish writing the `render` method so it returns a `div` element that contains an `h1` with the text `Hello React!`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The React component should return a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Enzyme.shallow(React.createElement(MyComponent)).type() === 'div');
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned `div` should render an `h1` header within it.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
/<div><h1>.*<\/h1><\/div>/.test(
|
||||||
|
Enzyme.shallow(React.createElement(MyComponent)).html()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `h1` header should contain the string `Hello React!`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
Enzyme.shallow(React.createElement(MyComponent)).html() ===
|
||||||
|
'<div><h1>Hello React!</h1></div>'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<MyComponent />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
// Change code below this line
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Hello React!</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
id: 587d7dbc367417b2b2512bb1
|
||||||
|
title: Create a Simple JSX Element
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301390
|
||||||
|
dashedName: create-a-simple-jsx-element
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
React is an Open Source view library created and maintained by Facebook. It's a great tool to render the User Interface (UI) of modern web applications.
|
||||||
|
|
||||||
|
React uses a syntax extension of JavaScript called JSX that allows you to write HTML directly within JavaScript. This has several benefits. It lets you use the full programmatic power of JavaScript within HTML, and helps to keep your code readable. For the most part, JSX is similar to the HTML that you have already learned, however there are a few key differences that will be covered throughout these challenges.
|
||||||
|
|
||||||
|
For instance, because JSX is a syntactic extension of JavaScript, you can actually write JavaScript directly within JSX. To do this, you simply include the code you want to be treated as JavaScript within curly braces: `{ 'this is treated as JavaScript code' }`. Keep this in mind, since it's used in several future challenges.
|
||||||
|
|
||||||
|
However, because JSX is not valid JavaScript, JSX code must be compiled into JavaScript. The transpiler Babel is a popular tool for this process. For your convenience, it's already added behind the scenes for these challenges. If you happen to write syntactically invalid JSX, you will see the first test in these challenges fail.
|
||||||
|
|
||||||
|
It's worth noting that under the hood the challenges are calling `ReactDOM.render(JSX, document.getElementById('root'))`. This function call is what places your JSX into React's own lightweight representation of the DOM. React then uses snapshots of its own DOM to optimize updating only specific parts of the actual DOM.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The current code uses JSX to assign a `div` element to the constant `JSX`. Replace the `div` with an `h1` element and add the text `Hello JSX!` inside it.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The constant `JSX` should return an `h1` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(JSX.type === 'h1');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `h1` tag should include the text `Hello JSX!`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Enzyme.shallow(JSX).contains('Hello JSX!'));
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(JSX, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = <div></div>;
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = <h1>Hello JSX!</h1>;
|
||||||
|
```
|
@ -0,0 +1,134 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036170
|
||||||
|
title: Create a Stateful Component
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301391
|
||||||
|
dashedName: create-a-stateful-component
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
One of the most important topics in React is `state`. State consists of any data your application needs to know about, that can change over time. You want your apps to respond to state changes and present an updated UI when necessary. React offers a nice solution for the state management of modern web applications.
|
||||||
|
|
||||||
|
You create state in a React component by declaring a `state` property on the component class in its `constructor`. This initializes the component with `state` when it is created. The `state` property must be set to a JavaScript `object`. Declaring it looks like this:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
this.state = {
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You have access to the `state` object throughout the life of your component. You can update it, render it in your UI, and pass it as props to child components. The `state` object can be as complex or as simple as you need it to be. Note that you must create a class component by extending `React.Component` in order to create `state` like this.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
There is a component in the code editor that is trying to render a `name` property from its `state`. However, there is no `state` defined. Initialize the component with `state` in the `constructor` and assign your name to a property of `name`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
`StatefulComponent` should exist and render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(
|
||||||
|
React.createElement(StatefulComponent)
|
||||||
|
);
|
||||||
|
return mockedComponent.find('StatefulComponent').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
`StatefulComponent` should render a `div` and an `h1` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(
|
||||||
|
React.createElement(StatefulComponent)
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
mockedComponent.find('div').length === 1 &&
|
||||||
|
mockedComponent.find('h1').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The state of `StatefulComponent` should be initialized with a property `name` set to a string.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(
|
||||||
|
React.createElement(StatefulComponent)
|
||||||
|
);
|
||||||
|
const initialState = mockedComponent.state();
|
||||||
|
return (
|
||||||
|
typeof initialState === 'object' && typeof initialState.name === 'string'
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The property `name` in the state of `StatefulComponent` should render in the `h1` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(
|
||||||
|
React.createElement(StatefulComponent)
|
||||||
|
);
|
||||||
|
const initialState = mockedComponent.state();
|
||||||
|
return mockedComponent.find('h1').text() === initialState.name;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<StatefulComponent />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class StatefulComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
// Only change code below this line
|
||||||
|
|
||||||
|
// Only change code above this line
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{this.state.name}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class StatefulComponent extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
name: 'freeCodeCamp!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{this.state.name}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036162
|
||||||
|
title: Create a Stateless Functional Component
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301392
|
||||||
|
dashedName: create-a-stateless-functional-component
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Components are the core of React. Everything in React is a component and here you will learn how to create one.
|
||||||
|
|
||||||
|
There are two ways to create a React component. The first way is to use a JavaScript function. Defining a component in this way creates a *stateless functional component*. The concept of state in an application will be covered in later challenges. For now, think of a stateless component as one that can receive data and render it, but does not manage or track changes to that data. (We'll cover the second way to create a React component in the next challenge.)
|
||||||
|
|
||||||
|
To create a component with a function, you simply write a JavaScript function that returns either JSX or `null`. One important thing to note is that React requires your function name to begin with a capital letter. Here's an example of a stateless functional component that assigns an HTML class in JSX:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const DemoComponent = function() {
|
||||||
|
return (
|
||||||
|
<div className='customClass' />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
After being transpiled, the `<div>` will have a CSS class of `customClass`.
|
||||||
|
|
||||||
|
Because a JSX component represents HTML, you could put several components together to create a more complex HTML page. This is one of the key advantages of the component architecture React provides. It allows you to compose your UI from many separate, isolated components. This makes it easier to build and maintain complex user interfaces.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has a function called `MyComponent`. Complete this function so it returns a single `div` element which contains some string of text.
|
||||||
|
|
||||||
|
**Note:** The text is considered a child of the `div` element, so you will not be able to use a self-closing tag.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
`MyComponent` should return JSX.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
return mockedComponent.length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
`MyComponent` should return a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
return mockedComponent.children().type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` element should contain a string of text.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
|
||||||
|
return mockedComponent.find('div').text() !== '';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<MyComponent />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const MyComponent = function() {
|
||||||
|
// Change code below this line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const MyComponent = function() {
|
||||||
|
// Change code below this line
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Demo Solution
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036160
|
||||||
|
title: Define an HTML Class in JSX
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301393
|
||||||
|
dashedName: define-an-html-class-in-jsx
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
Now that you're getting comfortable writing JSX, you may be wondering how it differs from HTML.
|
||||||
|
|
||||||
|
So far, it may seem that HTML and JSX are exactly the same.
|
||||||
|
|
||||||
|
One key difference in JSX is that you can no longer use the word `class` to define HTML classes. This is because `class` is a reserved word in JavaScript. Instead, JSX uses `className`.
|
||||||
|
|
||||||
|
In fact, the naming convention for all HTML attributes and event references in JSX become camelCase. For example, a click event in JSX is `onClick`, instead of `onclick`. Likewise, `onchange` becomes `onChange`. While this is a subtle difference, it is an important one to keep in mind moving forward.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Apply a class of `myDiv` to the `div` provided in the JSX code.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The constant `JSX` should return a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.strictEqual(JSX.type, 'div');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should have a class of `myDiv`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.strictEqual(JSX.props.className, 'myDiv');
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(JSX, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = (
|
||||||
|
<div>
|
||||||
|
<h1>Add a class to this div</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = (
|
||||||
|
<div className = 'myDiv'>
|
||||||
|
<h1>Add a class to this div</h1>
|
||||||
|
</div>);
|
||||||
|
```
|
@ -0,0 +1,147 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403618b
|
||||||
|
title: Give Sibling Elements a Unique Key Attribute
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301394
|
||||||
|
dashedName: give-sibling-elements-a-unique-key-attribute
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The last challenge showed how the `map` method is used to dynamically render a number of elements based on user input. However, there was an important piece missing from that example. When you create an array of elements, each one needs a `key` attribute set to a unique value. React uses these keys to keep track of which items are added, changed, or removed. This helps make the re-rendering process more efficient when the list is modified in any way.
|
||||||
|
|
||||||
|
**Note:** Keys only need to be unique between sibling elements, they don't need to be globally unique in your application.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The code editor has an array with some front end frameworks and a stateless functional component named `Frameworks()`. `Frameworks()` needs to map the array to an unordered list, much like in the last challenge. Finish writing the `map` callback to return an `li` element for each framework in the `frontEndFrameworks` array. This time, make sure to give each `li` a `key` attribute, set to a unique value. The `li` elements should also contain text from `frontEndFrameworks`.
|
||||||
|
|
||||||
|
Normally, you want to make the key something that uniquely identifies the element being rendered. As a last resort the array index may be used, but typically you should try to use a unique identification.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `Frameworks` component should exist and render to the page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
Enzyme.mount(React.createElement(Frameworks)).find('Frameworks').length === 1
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
`Frameworks` should render an `h1` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Enzyme.mount(React.createElement(Frameworks)).find('h1').length === 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
`Frameworks` should render a `ul` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Enzyme.mount(React.createElement(Frameworks)).find('ul').length === 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ul` tag should render 6 child `li` elements.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
Enzyme.mount(React.createElement(Frameworks)).find('ul').children().length ===
|
||||||
|
6 &&
|
||||||
|
Enzyme.mount(React.createElement(Frameworks))
|
||||||
|
.find('ul')
|
||||||
|
.childAt(0)
|
||||||
|
.name() === 'li' &&
|
||||||
|
Enzyme.mount(React.createElement(Frameworks)).find('li').length === 6
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each list item element should have a unique `key` attribute.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const ul = Enzyme.mount(React.createElement(Frameworks)).find('ul');
|
||||||
|
const keys = new Set([
|
||||||
|
ul.childAt(0).key(),
|
||||||
|
ul.childAt(1).key(),
|
||||||
|
ul.childAt(2).key(),
|
||||||
|
ul.childAt(3).key(),
|
||||||
|
ul.childAt(4).key(),
|
||||||
|
ul.childAt(5).key()
|
||||||
|
]);
|
||||||
|
return keys.size === 6;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each list item element should contain text from `frontEndFrameworks`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const li = Enzyme.mount(React.createElement(Frameworks))
|
||||||
|
.find('ul')
|
||||||
|
.children();
|
||||||
|
return [...Array(5)].every((_, i) =>
|
||||||
|
frontEndFrameworks.includes(li.at(i).text())
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<Frameworks />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const frontEndFrameworks = [
|
||||||
|
'React',
|
||||||
|
'Angular',
|
||||||
|
'Ember',
|
||||||
|
'Knockout',
|
||||||
|
'Backbone',
|
||||||
|
'Vue'
|
||||||
|
];
|
||||||
|
|
||||||
|
function Frameworks() {
|
||||||
|
const renderFrameworks = null; // Change this line
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Popular Front End JavaScript Frameworks</h1>
|
||||||
|
<ul>
|
||||||
|
{renderFrameworks}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const frontEndFrameworks = [
|
||||||
|
'React',
|
||||||
|
'Angular',
|
||||||
|
'Ember',
|
||||||
|
'Knockout',
|
||||||
|
'Backbone',
|
||||||
|
'Vue'
|
||||||
|
];
|
||||||
|
|
||||||
|
function Frameworks() {
|
||||||
|
const renderFrameworks = frontEndFrameworks.map((fw, i) => <li key={i}>{fw}</li>);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Popular Front End JavaScript Frameworks</h1>
|
||||||
|
<ul>
|
||||||
|
{renderFrameworks}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,104 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036181
|
||||||
|
title: Introducing Inline Styles
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301395
|
||||||
|
dashedName: introducing-inline-styles
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
There are other complex concepts that add powerful capabilities to your React code. But you may be wondering about the more simple problem of how to style those JSX elements you create in React. You likely know that it won't be exactly the same as working with HTML because of [the way you apply classes to JSX elements](/learn/front-end-libraries/react/define-an-html-class-in-jsx).
|
||||||
|
|
||||||
|
If you import styles from a stylesheet, it isn't much different at all. You apply a class to your JSX element using the `className` attribute, and apply styles to the class in your stylesheet. Another option is to apply inline styles, which are very common in ReactJS development.
|
||||||
|
|
||||||
|
You apply inline styles to JSX elements similar to how you do it in HTML, but with a few JSX differences. Here's an example of an inline style in HTML:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<div style="color: yellow; font-size: 16px">Mellow Yellow</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
JSX elements use the `style` attribute, but because of the way JSX is transpiled, you can't set the value to a `string`. Instead, you set it equal to a JavaScript `object`. Here's an example:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<div style={{color: "yellow", fontSize: 16}}>Mellow Yellow</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice how we camelCase the `fontSize` property? This is because React will not accept kebab-case keys in the style object. React will apply the correct property name for us in the HTML.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Add a `style` attribute to the `div` in the code editor to give the text a color of red and font size of `72px`.
|
||||||
|
|
||||||
|
Note that you can optionally set the font size to be a number, omitting the units `px`, or write it as `72px`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The component should render a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Colorful));
|
||||||
|
return mockedComponent.children().type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` element should have a color of `red`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Colorful));
|
||||||
|
return mockedComponent.children().props().style.color === 'red';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` element should have a font size of `72px`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Colorful));
|
||||||
|
return (
|
||||||
|
mockedComponent.children().props().style.fontSize === 72 ||
|
||||||
|
mockedComponent.children().props().style.fontSize === '72' ||
|
||||||
|
mockedComponent.children().props().style.fontSize === '72px'
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<Colorful />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class Colorful extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>Big Red</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class Colorful extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{color: "red", fontSize: 72}}>Big Red</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036161
|
||||||
|
title: Learn About Self-Closing JSX Tags
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301396
|
||||||
|
dashedName: learn-about-self-closing-jsx-tags
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
So far, you’ve seen how JSX differs from HTML in a key way with the use of `className` vs. `class` for defining HTML classes.
|
||||||
|
|
||||||
|
Another important way in which JSX differs from HTML is in the idea of the self-closing tag.
|
||||||
|
|
||||||
|
In HTML, almost all tags have both an opening and closing tag: `<div></div>`; the closing tag always has a forward slash before the tag name that you are closing. However, there are special instances in HTML called “self-closing tags”, or tags that don’t require both an opening and closing tag before another tag can start.
|
||||||
|
|
||||||
|
For example the line-break tag can be written as `<br>` or as `<br />`, but should never be written as `<br></br>`, since it doesn't contain any content.
|
||||||
|
|
||||||
|
In JSX, the rules are a little different. Any JSX element can be written with a self-closing tag, and every element must be closed. The line-break tag, for example, must always be written as `<br />` in order to be valid JSX that can be transpiled. A `<div>`, on the other hand, can be written as `<div />` or `<div></div>`. The difference is that in the first syntax version there is no way to include anything in the `<div />`. You will see in later challenges that this syntax is useful when rendering React components.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Fix the errors in the code editor so that it is valid JSX and successfully transpiles. Make sure you don't change any of the content - you only need to close tags where they are needed.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The constant `JSX` should return a `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.strictEqual(JSX.type, 'div');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should contain a `br` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Enzyme.shallow(JSX).find('br').length === 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `div` should contain an `hr` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(Enzyme.shallow(JSX).find('hr').length === 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(JSX, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = (
|
||||||
|
<div>
|
||||||
|
<h2>Welcome to React!</h2> <br >
|
||||||
|
<p>Be sure to close all tags!</p>
|
||||||
|
<hr >
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const JSX = (
|
||||||
|
<div>
|
||||||
|
<h2>Welcome to React!</h2> <br />
|
||||||
|
<p>Be sure to close all tags!</p>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
```
|
@ -0,0 +1,187 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036180
|
||||||
|
title: Optimize Re-Renders with shouldComponentUpdate
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301398
|
||||||
|
dashedName: optimize-re-renders-with-shouldcomponentupdate
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
So far, if any component receives new `state` or new `props`, it re-renders itself and all its children. This is usually okay. But React provides a lifecycle method you can call when child components receive new `state` or `props`, and declare specifically if the components should update or not. The method is `shouldComponentUpdate()`, and it takes `nextProps` and `nextState` as parameters.
|
||||||
|
|
||||||
|
This method is a useful way to optimize performance. For example, the default behavior is that your component re-renders when it receives new `props`, even if the `props` haven't changed. You can use `shouldComponentUpdate()` to prevent this by comparing the `props`. The method must return a `boolean` value that tells React whether or not to update the component. You can compare the current props (`this.props`) to the next props (`nextProps`) to determine if you need to update or not, and return `true` or `false` accordingly.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The `shouldComponentUpdate()` method is added in a component called `OnlyEvens`. Currently, this method returns `true` so `OnlyEvens` re-renders every time it receives new `props`. Modify the method so `OnlyEvens` updates only if the `value` of its new props is even. Click the `Add` button and watch the order of events in your browser's console as the lifecycle hooks are triggered.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `Controller` component should render the `OnlyEvens` component as a child.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Controller));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('Controller').length === 1 &&
|
||||||
|
mockedComponent.find('OnlyEvens').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `shouldComponentUpdate` method should be defined on the `OnlyEvens` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(() => {
|
||||||
|
const child = React.createElement(OnlyEvens)
|
||||||
|
.type.prototype.shouldComponentUpdate.toString()
|
||||||
|
.replace(/s/g, '');
|
||||||
|
return child !== 'undefined';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `OnlyEvens` component should return an `h1` tag which renders the value of `this.props.value`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Controller));
|
||||||
|
const first = () => {
|
||||||
|
mockedComponent.setState({ value: 1000 });
|
||||||
|
return mockedComponent.find('h1').html();
|
||||||
|
};
|
||||||
|
const second = () => {
|
||||||
|
mockedComponent.setState({ value: 10 });
|
||||||
|
return mockedComponent.find('h1').html();
|
||||||
|
};
|
||||||
|
const firstValue = first();
|
||||||
|
const secondValue = second();
|
||||||
|
assert(firstValue === '<h1>1000</h1>' && secondValue === '<h1>10</h1>');
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
`OnlyEvens` should re-render only when `nextProps.value` is even.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(() => {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Controller));
|
||||||
|
const first = () => {
|
||||||
|
mockedComponent.setState({ value: 8 });
|
||||||
|
return mockedComponent.find('h1').text();
|
||||||
|
};
|
||||||
|
const second = () => {
|
||||||
|
mockedComponent.setState({ value: 7 });
|
||||||
|
return mockedComponent.find('h1').text();
|
||||||
|
};
|
||||||
|
const third = () => {
|
||||||
|
mockedComponent.setState({ value: 42 });
|
||||||
|
return mockedComponent.find('h1').text();
|
||||||
|
};
|
||||||
|
const firstValue = first();
|
||||||
|
const secondValue = second();
|
||||||
|
const thirdValue = third();
|
||||||
|
assert(firstValue === '8' && secondValue === '8' && thirdValue === '42');
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<Controller />, document.getElementById('root'));
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class OnlyEvens extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
console.log('Should I update?');
|
||||||
|
// Change code below this line
|
||||||
|
return true;
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
componentDidUpdate() {
|
||||||
|
console.log('Component re-rendered.');
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return <h1>{this.props.value}</h1>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Controller extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
value: 0
|
||||||
|
};
|
||||||
|
this.addValue = this.addValue.bind(this);
|
||||||
|
}
|
||||||
|
addValue() {
|
||||||
|
this.setState(state => ({
|
||||||
|
value: state.value + 1
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button onClick={this.addValue}>Add</button>
|
||||||
|
<OnlyEvens value={this.state.value} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class OnlyEvens extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
console.log('Should I update?');
|
||||||
|
// Change code below this line
|
||||||
|
return nextProps.value % 2 === 0;
|
||||||
|
// Change code above this line
|
||||||
|
}
|
||||||
|
componentDidUpdate() {
|
||||||
|
console.log('Component re-rendered.');
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return <h1>{this.props.value}</h1>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Controller extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
value: 0
|
||||||
|
};
|
||||||
|
this.addValue = this.addValue.bind(this);
|
||||||
|
}
|
||||||
|
addValue() {
|
||||||
|
this.setState(state => ({
|
||||||
|
value: state.value + 1
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button onClick={this.addValue}>Add</button>
|
||||||
|
<OnlyEvens value={this.state.value} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403616c
|
||||||
|
title: Override Default Props
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301399
|
||||||
|
dashedName: override-default-props
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The ability to set default props is a useful feature in React. The way to override the default props is to explicitly set the prop values for a component.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The `ShoppingCart` component now renders a child component `Items`. This `Items` component has a default prop `quantity` set to the integer `0`. Override the default prop by passing in a value of `10` for `quantity`.
|
||||||
|
|
||||||
|
**Note:** Remember that the syntax to add a prop to a component looks similar to how you add HTML attributes. However, since the value for `quantity` is an integer, it won't go in quotes but it should be wrapped in curly braces. For example, `{100}`. This syntax tells JSX to interpret the value within the braces directly as JavaScript.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The component `ShoppingCart` should render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart));
|
||||||
|
return mockedComponent.find('ShoppingCart').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The component `Items` should render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart));
|
||||||
|
return mockedComponent.find('Items').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Items` component should have a prop of `{ quantity: 10 }` passed from the `ShoppingCart` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
(getUserInput) =>
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('Items').props().quantity == 10 &&
|
||||||
|
getUserInput('index')
|
||||||
|
.replace(/ /g, '')
|
||||||
|
.includes('<Itemsquantity={10}/>')
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<ShoppingCart />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const Items = (props) => {
|
||||||
|
return <h1>Current Quantity of Items in Cart: {props.quantity}</h1>
|
||||||
|
}
|
||||||
|
|
||||||
|
Items.defaultProps = {
|
||||||
|
quantity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShoppingCart extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
return <Items />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const Items = (props) => {
|
||||||
|
return <h1>Current Quantity of Items in Cart: {props.quantity}</h1>
|
||||||
|
}
|
||||||
|
|
||||||
|
Items.defaultProps = {
|
||||||
|
quantity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShoppingCart extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
return <Items quantity = {10} />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,217 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403617b
|
||||||
|
title: Pass a Callback as Props
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301400
|
||||||
|
dashedName: pass-a-callback-as-props
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You can pass `state` as props to child components, but you're not limited to passing data. You can also pass handler functions or any method that's defined on a React component to a child component. This is how you allow child components to interact with their parent components. You pass methods to a child just like a regular prop. It's assigned a name and you have access to that method name under `this.props` in the child component.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
There are three components outlined in the code editor. The `MyApp` component is the parent that will render the `GetInput` and `RenderInput` child components. Add the `GetInput` component to the render method in `MyApp`, then pass it a prop called `input` assigned to `inputValue` from `MyApp`'s `state`. Also create a prop called `handleChange` and pass the input handler `handleChange` to it.
|
||||||
|
|
||||||
|
Next, add `RenderInput` to the render method in `MyApp`, then create a prop called `input` and pass the `inputValue` from `state` to it. Once you are finished you will be able to type in the `input` field in the `GetInput` component, which then calls the handler method in its parent via props. This updates the input in the `state` of the parent, which is passed as props to both children. Observe how the data flows between the components and how the single source of truth remains the `state` of the parent component. Admittedly, this example is a bit contrived, but should serve to illustrate how data and callbacks can be passed between React components.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `MyApp` component should render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
return mockedComponent.find('MyApp').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `GetInput` component should render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
return mockedComponent.find('GetInput').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `RenderInput` component should render.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
return mockedComponent.find('RenderInput').length === 1;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `GetInput` component should receive the `MyApp` state property `inputValue` as props and contain an `input` element which modifies `MyApp` state.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
const state_1 = () => {
|
||||||
|
mockedComponent.setState({ inputValue: '' });
|
||||||
|
return waitForIt(() => mockedComponent.state());
|
||||||
|
};
|
||||||
|
const state_2 = () => {
|
||||||
|
mockedComponent
|
||||||
|
.find('input')
|
||||||
|
.simulate('change', { target: { value: 'TestInput' } });
|
||||||
|
return waitForIt(() => mockedComponent.state());
|
||||||
|
};
|
||||||
|
const updated_1 = await state_1();
|
||||||
|
const updated_2 = await state_2();
|
||||||
|
assert(updated_1.inputValue === '' && updated_2.inputValue === 'TestInput');
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `RenderInput` component should receive the `MyApp` state property `inputValue` as props.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
const state_1 = () => {
|
||||||
|
mockedComponent.setState({ inputValue: 'TestName' });
|
||||||
|
return waitForIt(() => mockedComponent);
|
||||||
|
};
|
||||||
|
const updated_1 = await state_1();
|
||||||
|
assert(updated_1.find('p').text().includes('TestName'));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<MyApp />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyApp extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
inputValue: ''
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
inputValue: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GetInput extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Get Input:</h3>
|
||||||
|
<input
|
||||||
|
value={this.props.input}
|
||||||
|
onChange={this.props.handleChange}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderInput extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Input Render:</h3>
|
||||||
|
<p>{this.props.input}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyApp extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
inputValue: ''
|
||||||
|
}
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({
|
||||||
|
inputValue: event.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<GetInput
|
||||||
|
input={this.state.inputValue}
|
||||||
|
handleChange={this.handleChange}/>
|
||||||
|
<RenderInput
|
||||||
|
input={this.state.inputValue}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GetInput extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Get Input:</h3>
|
||||||
|
<input
|
||||||
|
value={this.props.input}
|
||||||
|
onChange={this.props.handleChange}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderInput extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Input Render:</h3>
|
||||||
|
<p>{this.props.input}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,186 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403616a
|
||||||
|
title: Pass an Array as Props
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301401
|
||||||
|
dashedName: pass-an-array-as-props
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The last challenge demonstrated how to pass information from a parent component to a child component as `props` or properties. This challenge looks at how arrays can be passed as `props`. To pass an array to a JSX element, it must be treated as JavaScript and wrapped in curly braces.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<ParentComponent>
|
||||||
|
<ChildComponent colors={["green", "blue", "red"]} />
|
||||||
|
</ParentComponent>
|
||||||
|
```
|
||||||
|
|
||||||
|
The child component then has access to the array property `colors`. Array methods such as `join()` can be used when accessing the property. `const ChildComponent = (props) => <p>{props.colors.join(', ')}</p>` This will join all `colors` array items into a comma separated string and produce: `<p>green, blue, red</p>` Later, we will learn about other common methods to render arrays of data in React.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
There are `List` and `ToDo` components in the code editor. When rendering each `List` from the `ToDo` component, pass in a `tasks` property assigned to an array of to-do tasks, for example `["walk dog", "workout"]`. Then access this `tasks` array in the `List` component, showing its value within the `p` element. Use `join(", ")` to display the `props.tasks`array in the `p` element as a comma separated list. Today's list should have at least 2 tasks and tomorrow's should have at least 3 tasks.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `ToDo` component should return a single outer `div`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ToDo));
|
||||||
|
return mockedComponent.children().first().type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The third child of the `ToDo` component should be an instance of the `List` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ToDo));
|
||||||
|
return mockedComponent.children().first().childAt(2).name() === 'List';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The fifth child of the `ToDo` component should be an instance of the `List` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ToDo));
|
||||||
|
return mockedComponent.children().first().childAt(4).name() === 'List';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Both instances of the `List` component should have a property called `tasks` and `tasks` should be of type array.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ToDo));
|
||||||
|
return (
|
||||||
|
Array.isArray(mockedComponent.find('List').get(0).props.tasks) &&
|
||||||
|
Array.isArray(mockedComponent.find('List').get(1).props.tasks)
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The first `List` component representing the tasks for today should have 2 or more items.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ToDo));
|
||||||
|
return mockedComponent.find('List').get(0).props.tasks.length >= 2;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The second `List` component representing the tasks for tomorrow should have 3 or more items.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ToDo));
|
||||||
|
return mockedComponent.find('List').get(1).props.tasks.length >= 3;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `List` component should render the value from the `tasks` prop in the `p` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(ToDo));
|
||||||
|
return (
|
||||||
|
mockedComponent
|
||||||
|
.find('p')
|
||||||
|
.get(0)
|
||||||
|
.props.children.replace(/\s*,\s*/g, ',') ===
|
||||||
|
mockedComponent
|
||||||
|
.find('List')
|
||||||
|
.get(0)
|
||||||
|
.props.tasks.join(',')
|
||||||
|
.replace(/\s*,\s*/g, ',') &&
|
||||||
|
mockedComponent
|
||||||
|
.find('p')
|
||||||
|
.get(1)
|
||||||
|
.props.children.replace(/\s*,\s*/g, ',') ===
|
||||||
|
mockedComponent
|
||||||
|
.find('List')
|
||||||
|
.get(1)
|
||||||
|
.props.tasks.join(',')
|
||||||
|
.replace(/\s*,\s*/g, ',')
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<ToDo />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const List = (props) => {
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
return <p>{}</p>
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ToDo extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>To Do Lists</h1>
|
||||||
|
<h2>Today</h2>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<List/>
|
||||||
|
<h2>Tomorrow</h2>
|
||||||
|
<List/>
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const List= (props) => {
|
||||||
|
return <p>{props.tasks.join(', ')}</p>
|
||||||
|
};
|
||||||
|
|
||||||
|
class ToDo extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>To Do Lists</h1>
|
||||||
|
<h2>Today</h2>
|
||||||
|
<List tasks={['study', 'exercise']} />
|
||||||
|
<h2>Tomorrow</h2>
|
||||||
|
<List tasks={['call Sam', 'grocery shopping', 'order tickets']} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,164 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036169
|
||||||
|
title: Pass Props to a Stateless Functional Component
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301402
|
||||||
|
dashedName: pass-props-to-a-stateless-functional-component
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
The previous challenges covered a lot about creating and composing JSX elements, functional components, and ES6 style class components in React. With this foundation, it's time to look at another feature very common in React: **props**. In React, you can pass props, or properties, to child components. Say you have an `App` component which renders a child component called `Welcome` which is a stateless functional component. You can pass `Welcome` a `user` property by writing:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<App>
|
||||||
|
<Welcome user='Mark' />
|
||||||
|
</App>
|
||||||
|
```
|
||||||
|
|
||||||
|
You use **custom HTML attributes** created by you and supported by React to be passed to the component. In this case, the created property `user` is passed to the component `Welcome`. Since `Welcome` is a stateless functional component, it has access to this value like so:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const Welcome = (props) => <h1>Hello, {props.user}!</h1>
|
||||||
|
```
|
||||||
|
|
||||||
|
It is standard to call this value `props` and when dealing with stateless functional components, you basically consider it as an argument to a function which returns JSX. You can access the value of the argument in the function body. With class components, you will see this is a little different.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
There are `Calendar` and `CurrentDate` components in the code editor. When rendering `CurrentDate` from the `Calendar` component, pass in a property of `date` assigned to the current date from JavaScript's `Date` object. Then access this `prop` in the `CurrentDate` component, showing its value within the `p` tags. Note that for `prop` values to be evaluated as JavaScript, they must be enclosed in curly brackets, for instance `date={Date()}`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `Calendar` component should return a single `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Calendar));
|
||||||
|
return mockedComponent.children().type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The second child of the `Calendar` component should be the `CurrentDate` component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Calendar));
|
||||||
|
return mockedComponent.children().childAt(1).name() === 'CurrentDate';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `CurrentDate` component should have a prop called `date`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Calendar));
|
||||||
|
return mockedComponent.children().childAt(1).props().date;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `date` prop of the `CurrentDate` should contain a string of text.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(Calendar));
|
||||||
|
const prop = mockedComponent.children().childAt(1).props().date;
|
||||||
|
return typeof prop === 'string' && prop.length > 0;
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `date` prop should be generated by calling `Date()`
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(/<CurrentDatedate={Date\(\)}\/>/.test(__helpers.removeWhiteSpace(code)));
|
||||||
|
```
|
||||||
|
|
||||||
|
The `CurrentDate` component should render the value from the `date` prop in the `p` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
let date = 'dummy date';
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(
|
||||||
|
React.createElement(CurrentDate, { date })
|
||||||
|
);
|
||||||
|
return mockedComponent.find('p').html().includes(date);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<Calendar />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const CurrentDate = (props) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<p>The current date is: </p>
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Calendar extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>What date is it?</h3>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<CurrentDate />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const CurrentDate = (props) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<p>The current date is: {props.date}</p>
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Calendar extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>What date is it?</h3>
|
||||||
|
{ /* Change code below this line */ }
|
||||||
|
<CurrentDate date={Date()} />
|
||||||
|
{ /* Change code above this line */ }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,145 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d403617a
|
||||||
|
title: Pass State as Props to Child Components
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301403
|
||||||
|
dashedName: pass-state-as-props-to-child-components
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You saw a lot of examples that passed props to child JSX elements and child React components in previous challenges. You may be wondering where those props come from. A common pattern is to have a stateful component containing the `state` important to your app, that then renders child components. You want these components to have access to some pieces of that `state`, which are passed in as props.
|
||||||
|
|
||||||
|
For example, maybe you have an `App` component that renders a `Navbar`, among other components. In your `App`, you have `state` that contains a lot of user information, but the `Navbar` only needs access to the user's username so it can display it. You pass that piece of `state` to the `Navbar` component as a prop.
|
||||||
|
|
||||||
|
This pattern illustrates some important paradigms in React. The first is *unidirectional data flow*. State flows in one direction down the tree of your application's components, from the stateful parent component to child components. The child components only receive the state data they need. The second is that complex stateful apps can be broken down into just a few, or maybe a single, stateful component. The rest of your components simply receive state from the parent as props, and render a UI from that state. It begins to create a separation where state management is handled in one part of code and UI rendering in another. This principle of separating state logic from UI logic is one of React's key principles. When it's used correctly, it makes the design of complex, stateful applications much easier to manage.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
The `MyApp` component is stateful and renders a `Navbar` component as a child. Pass the `name` property in its `state` down to the child component, then show the `name` in the `h1` tag that's part of the `Navbar` render method. `name` should appear after the text `Hello, my name is:`.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `MyApp` component should render with a `Navbar` component inside.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
return (
|
||||||
|
mockedComponent.find('MyApp').length === 1 &&
|
||||||
|
mockedComponent.find('Navbar').length === 1
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Navbar` component should receive the `MyApp` state property `name` as props.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
const setState = () => {
|
||||||
|
mockedComponent.setState({ name: 'TestName' });
|
||||||
|
return waitForIt(() => mockedComponent.find('Navbar').props());
|
||||||
|
};
|
||||||
|
const navProps = await setState();
|
||||||
|
assert(navProps.name === 'TestName');
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `h1` element in `Navbar` should render the `name` prop.
|
||||||
|
|
||||||
|
```js
|
||||||
|
async () => {
|
||||||
|
const waitForIt = (fn) =>
|
||||||
|
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(MyApp));
|
||||||
|
const navH1Before = mockedComponent.find('Navbar').find('h1').text();
|
||||||
|
const setState = () => {
|
||||||
|
mockedComponent.setState({ name: 'TestName' });
|
||||||
|
return waitForIt(() => mockedComponent.find('Navbar').find('h1').text());
|
||||||
|
};
|
||||||
|
const navH1After = await setState();
|
||||||
|
assert(new RegExp('TestName').test(navH1After) && navH1After !== navH1Before);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --after-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<MyApp />, document.getElementById('root'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyApp extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
name: 'CamperBot'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Change code below this line */}
|
||||||
|
<Navbar />
|
||||||
|
{/* Change code above this line */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Navbar extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Change code below this line */}
|
||||||
|
<h1>Hello, my name is: </h1>
|
||||||
|
{/* Change code above this line */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyApp extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
name: 'CamperBot'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Navbar name={this.state.name}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class Navbar extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Hello, my name is: {this.props.name}</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1,159 @@
|
|||||||
|
---
|
||||||
|
id: 5a24c314108439a4d4036167
|
||||||
|
title: Render a Class Component to the DOM
|
||||||
|
challengeType: 6
|
||||||
|
forumTopicId: 301404
|
||||||
|
dashedName: render-a-class-component-to-the-dom
|
||||||
|
---
|
||||||
|
|
||||||
|
# --description--
|
||||||
|
|
||||||
|
You may remember using the ReactDOM API in an earlier challenge to render JSX elements to the DOM. The process for rendering React components will look very similar. The past few challenges focused on components and composition, so the rendering was done for you behind the scenes. However, none of the React code you write will render to the DOM without making a call to the ReactDOM API.
|
||||||
|
|
||||||
|
Here's a refresher on the syntax: `ReactDOM.render(componentToRender, targetNode)`. The first argument is the React component that you want to render. The second argument is the DOM node that you want to render that component within.
|
||||||
|
|
||||||
|
React components are passed into `ReactDOM.render()` a little differently than JSX elements. For JSX elements, you pass in the name of the element that you want to render. However, for React components, you need to use the same syntax as if you were rendering a nested component, for example `ReactDOM.render(<ComponentToRender />, targetNode)`. You use this syntax for both ES6 class components and functional components.
|
||||||
|
|
||||||
|
# --instructions--
|
||||||
|
|
||||||
|
Both the `Fruits` and `Vegetables` components are defined for you behind the scenes. Render both components as children of the `TypesOfFood` component, then render `TypesOfFood` to the DOM. There is a `div` with `id='challenge-node'` available for you to use.
|
||||||
|
|
||||||
|
# --hints--
|
||||||
|
|
||||||
|
The `TypesOfFood` component should return a single `div` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
|
||||||
|
return mockedComponent.children().type() === 'div';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `TypesOfFood` component should render the `Fruits` component after the `h1` element.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
|
||||||
|
return mockedComponent.children().childAt(1).name() === 'Fruits';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `TypesOfFood` component should render the `Vegetables` component after `Fruits`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
|
||||||
|
return mockedComponent.children().childAt(2).name() === 'Vegetables';
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `TypesOfFood` component should render to the DOM within the `div` with the id `challenge-node`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert(
|
||||||
|
(function () {
|
||||||
|
const html = document.getElementById('challenge-node').childNodes[0]
|
||||||
|
.innerHTML;
|
||||||
|
return (
|
||||||
|
html.includes(
|
||||||
|
'<div><h2>Fruits:</h2><h4>Non-Citrus:</h4><ul><li>Apples</li><li>Blueberries</li><li>Strawberries</li><li>Bananas</li></ul><h4>Citrus:</h4><ul><li>Lemon</li><li>Lime</li><li>Orange</li><li>Grapefruit</li></ul></div>'
|
||||||
|
) &&
|
||||||
|
html.includes(
|
||||||
|
'<div><h2>Vegetables:</h2><ul><li>Brussel Sprouts</li><li>Broccoli</li><li>Squash</li></ul></div>'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
# --seed--
|
||||||
|
|
||||||
|
## --before-user-code--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const Fruits = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Fruits:</h2>
|
||||||
|
<h4>Non-Citrus:</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Apples</li>
|
||||||
|
<li>Blueberries</li>
|
||||||
|
<li>Strawberries</li>
|
||||||
|
<li>Bananas</li>
|
||||||
|
</ul>
|
||||||
|
<h4>Citrus:</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Lemon</li>
|
||||||
|
<li>Lime</li>
|
||||||
|
<li>Orange</li>
|
||||||
|
<li>Grapefruit</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const Vegetables = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Vegetables:</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Brussel Sprouts</li>
|
||||||
|
<li>Broccoli</li>
|
||||||
|
<li>Squash</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## --seed-contents--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class TypesOfFood extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Types of Food:</h1>
|
||||||
|
{/* Change code below this line */}
|
||||||
|
|
||||||
|
{/* Change code above this line */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
```
|
||||||
|
|
||||||
|
# --solutions--
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class TypesOfFood extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Types of Food:</h1>
|
||||||
|
{/* Change code below this line */}
|
||||||
|
<Fruits />
|
||||||
|
<Vegetables />
|
||||||
|
{/* Change code above this line */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change code below this line
|
||||||
|
ReactDOM.render(<TypesOfFood />, document.getElementById('challenge-node'));
|
||||||
|
```
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user