How can I pass data between controllers in AngularJS? - javascript
I need to keep two separate controllers, one for a search area and one to display data. When a search is performed I need to fetch data from the internet and update the view with the new data. I don't want to wrap everything with a bigger controller or something like that (is this best practice?) but I'd prefer the search and display controllers to remain completely separate.
This is the html code relative to the search field and display grid
<div id="mainContainer" class="container-fluid" >
<div id="searchContainer">
<div id="search" ng-controller="SearchController as srcCtrl">
<!-- on submit call submit(title) -->
<form class="navbar-form" role="search">
<div class="input-group">
<input ng-model="title" type="text" class="form-control" placeholder="Search" name="srch-term" id="srch-term">
<div class="input-group-btn">
<button class="btn btn-default" ng-click="srcCtrl(title)"><i class="glyphicon glyphicon-search"></i></button>
</div>
</div>
</form>
</div>
</div>
<div id="animeContainer" class="container-fluid">
<div class="clearfix"></div>
<!-- animeContainer directive -->
<anime-container></anime-container>
</div>
</div>
And the Angular code:
(function(){
var app = angular.module('hummingbird', []);
app.controller('AnimeListController', function(){
this.anime = animeList; //list of anime to display in anime list
this.onSelectAnime = function(anime){
console.log(anime);
};
});
app.controller('SearchController', function(){
this.submit = function(srcstr){
//here I call the API and then I want to update the anime variable in AnimeListController
console.log(srcstr);
}
});
app.directive("animeContainer", function(){
return{
restrict: 'E',
templateUrl: 'anime-container.html',
}
});
var animeList = [{"id":25,"slug":"ghost-in-the-shell","status":"Finished Airing","url":"https://hummingbird.me/anime/ghost-in-the-shell","title":"Ghost in the Shell","alternate_title":null,"episode_count":1,"cover_image":"https://static.hummingbird.me/anime/poster_images/000/000/025/large/25.jpg?1408440508","synopsis":"In the year 2029, the barriers of our world have been broken down by the net and by cybernetics, but this brings new vulnerability to humans in the form of brain-hacking. When a highly-wanted hacker known as 'The Puppetmaster' begins involving them in politics, Section 9, a group of cybernetically enhanced cops, are called in to investigate and stop the Puppetmaster. The pursuit will call into question what makes a human and what is the Puppetmaster in a world where the distinction between human and machine is increasingly blurry.\n(Source: ANN)","show_type":"Movie"},{"id":1411,"slug":"ghost-hunt","status":"Finished Airing","url":"https://hummingbird.me/anime/ghost-hunt","title":"Ghost Hunt","alternate_title":"","episode_count":25,"cover_image":"https://static.hummingbird.me/anime/poster_images/000/001/411/large/1411.jpg?1408443952","synopsis":"Telling ghost stories is a favorite past time of Mai Taniyama and her friends—that is, until she meets 17-year-old Kazuya Shibuya, the man sent by Shibuya Psychic Research Center to investigate paranormal activity at a supposedly haunted school. When Mai gets caught in a dangerous situation, she is rescued by Kazuya's assistant. Saving her lands the assistant incapacitated, and Kazuya demands that Mai become his assistant, instead. (Source: ANN)","show_type":"TV"},{"id":4135,"slug":"seven-ghost","status":"Finished Airing","url":"https://hummingbird.me/anime/seven-ghost","title":"07-Ghost","alternate_title":"","episode_count":25,"cover_image":"https://static.hummingbird.me/anime/poster_images/000/004/135/large/4135.jpg?1408451649","synopsis":"Set in a gothic fantasy world, this is the story of Teito Klein, an orphaned slave who became the top military academy student. However, an unexpected turn of events left him pursued by the forces of the Barsburg Empire. Now an escaping convict, Teito's sheltered by the church and its law of sanctuary. Here, he discovered many mysteries surrounding himself, the church, and the Empire itself. The fact that he might be connected to a dethroned king and the mystical stone of god, \"The Eye of Mikhael\", made him the target of the empire more than ever. Fortunately the church is under the mythical 7 Ghost protection. But who are the Ghosts really. Will Teito be free from the military's clutch, and what of his said mission to uncover the history. And who is the military's Chief-of-Staff Ayanami exactly. Teito's future seems to have spiraled into an unexpectedly perilous path.\r\n[Source: ANN]","show_type":"TV"},{"id":6391,"slug":"ghost-messenger","status":"Currently Airing","url":"https://hummingbird.me/anime/ghost-messenger","title":"Ghost Messenger","alternate_title":null,"episode_count":6,"cover_image":"https://static.hummingbird.me/anime/poster_images/000/006/391/large/6391.jpg?1408458272","synopsis":"Ghost Messengers are super-power agents from the underground world called the World of Death. The World of Death is a digitalized world with cutting-edge technologies that control and manage the life and death of all living things based on its elaborate systems.\r\nOur Ghost Messenger hero, Kang-lim, has been dispatched to the human world to capture the remaining ghosts who are refusing to go to the World of Death although it is their time.\r\nAn accident occurs during his mission and Kang-lim gets captured in his own mobile phone. Little Kang-lim, a human boy who has extraordinary spiritual powers, finds the mobile phone and takes GhostMessenger Kang-lim out from the mobile phone.\r\nAnd the adventure begins.\r\n(Source: Anime World Network)","show_type":"OVA"},{"id":2360,"slug":"shinreigari-ghost-hound","status":"Finished Airing","url":"https://hummingbird.me/anime/shinreigari-ghost-hound","title":"Shinreigari: Ghost Hound","alternate_title":null,"episode_count":22,"cover_image":"https://static.hummingbird.me/anime/poster_images/000/002/360/large/2360.jpg?1408446509","synopsis":"In an isolated region of Kyushu lies the town of Suiten. Though seeming small and modest, Suiten is not a picturesque place for a vacation, unless it is from the “Unseen Worldâ€. Taro, Makoto and Masayuki, three boys with traumatic pasts, learn to let their souls cross between the two parallel worlds. However, the Unseen World is no mere copy of the real Apparent World. The Unseen World is the home of ghosts, but changes are now allowing the souls of the dead to pass over into the Apparent World, with unpredictable effects. Follow the journey of Taro, Makoto and Masayuki, as they cross between the two worlds, trying to unravel a great mystery. \n(Source: Sentai Filmworks)","show_type":"TV"}];
})();
anime-container-html
<div class="col-md-3 col-xs-6" ng-repeat="anime in animeListCtrl.anime">
<!-- anime in anime list-->
<div class="panel panel-default fixed-height highlight" ng-click="animeListCtrl.onSelectAnime(anime)">
<div class="panel-body">
<img class="img-rounded img-responsive center-block" ng-src="{{anime.cover_image}}"/>
<h3> {{anime.title}} </h3>
</div>
</div>
</div>
I'm sure there's a pretty simple solution but I only find something that seems using old versions of AngularJS (I'm using 1.2.26).
Thanks everybody!
P.S. any other tip or advice about best practices are welcome!
What you want to do is add a service that you can then inject into your other controllers/directives. In your example, I imagine something like SearchService would work. In your submit function, rather than invoking the API directly have it call into the SearchService to execute the search. The SearchService would then maintain and expose the result set. Any controller and/or directive interested in displaying the results could bind to SearchService.resultSet, for instance.
Remember that Angular services are singleton objects. So if you intend on having more than a single search form/result object you may need to enhance your service to store named searches. However, based on the code you've shown, it looks like a single resultset would suffice. You could, optionally, decorate the ctrl,directive,service as part of an anime-specific module. So instead of SearchService call it AnimeSearchService.
app.factory('AnimeSearchService', function($http) {
var service = { resultSet: {} };
service.executeSearch = function(args) {
... some API calls ...
// when they return results store them as service.resultSet
}
return service;
});
Then in your controller
app.controller('AnimeSearchController', function(AnimeSearchService){
this.submit = function(srcstr){
//here I call the API and then I want to update the anime variable in AnimeListController
AnimeSearchService.executeSearch(srcstr);
console.log(srcstr);
}
});
app.controller('AnimeListController', function(AnimeSearchService){
this.anime = AnimeSearchService.resultSet; //expose the service to the template (or optionally create a $watch to update)
this.onSelectAnime = function(anime){
console.log(anime);
};
});
UPDATE: Your issue most likely comes down to angular bindings. If you are binding to properties of the service's resultSet object then those bindings will update as those properties change. However, if you are assigning the value of a property to a new property in your own controller/scope then you will have to watch the service and update your controller/scope's copy. Perhaps this fiddle will help explain it better: http://jsfiddle.net/vv3odc7t/1/
There is also this stack overflow question about service binding in general: https://stackoverflow.com/a/23774843/1769529
Hope that helps!
Related
Unable to Clear 'Search' results
I am looking to clear Search results when a new query is entered in the websites search bar. For example I am developing a TV search website, if I search 'Friends' a list of results will display however if I enter a new query the results will not clear and print at the bottom of the previous list of results. I have tried features such as resultList.innerHTML = ''; Here is some of my JavaScript: fetch(`https: //api.tvmaze.com/search/shows?q=${TVShow}`) .then((response) => response.json()) .then((data) => { for (const value of data) { document.querySelector(".TVShowInfo").insertAdjacentHTML('beforeend', `<div id="TVShow"> <center> <h1>${value.show.name}</h1> </center> </div>`); } }) <div class="searchBox"> <input id="TVShowName" type="TV show information" placeholder="Search for a TV show..." /> <button id="search">Search</button> </div> <div class="TVShowInfo"></div>
Try this - just replace the innerHTML instead of insertAdjacentHTML. I also changed the ID to class and removed the deprecated center document.querySelector(".TVShowInfo").innerHTML = data .map(({show}) => `<div class="TVShow"><h1>${show.name}</h1></div>`).join('<br/>'); .TVShow { text-align: center; } <div class="TVShowInfo"></div> <script> const data = [{"score":0.9089527,"show":{"id":431,"url":"https://www.tvmaze.com/shows/431/friends","name":"Friends","type":"Scripted","language":"English","genres":["Comedy","Romance"],"status":"Ended","runtime":30,"averageRuntime":30,"premiered":"1994-09-22","ended":"2004-05-06","officialSite":null,"schedule":{"time":"20:00","days":["Thursday"]},"rating":{"average":8.5},"weight":98,"network":{"id":1,"name":"NBC","country":{"name":"United States","code":"US","timezone":"America/New_York"},"officialSite":"https://www.nbc.com/"},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":3616,"thetvdb":79168,"imdb":"tt0108778"},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/41/104550.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/41/104550.jpg"},"summary":"<p>Six young (20-something) people from New York City (Manhattan), on their own and struggling to survive in the real world, find the companionship, comfort and support they get from each other to be the perfect antidote to the pressures of life.</p><p>This average group of buddies goes through massive mayhem, family trouble, past and future romances, fights, laughs, tears and surprises as they learn what it really means to be a friend.</p>","updated":1641068842,"_links":{"self":{"href":"https://api.tvmaze.com/shows/431"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/40881"}}}},{"score":0.8193341,"show":{"id":46948,"url":"https://www.tvmaze.com/shows/46948/friends","name":"Friends","type":"Scripted","language":"English","genres":["Drama","Comedy"],"status":"Ended","runtime":60,"averageRuntime":60,"premiered":"1979-03-25","ended":"1979-04-22","officialSite":null,"schedule":{"time":"","days":["Sunday"]},"rating":{"average":null},"weight":21,"network":{"id":3,"name":"ABC","country":{"name":"United States","code":"US","timezone":"America/New_York"},"officialSite":"https://"+"abc.com/"},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":76973,"imdb":"tt0078615"},"image":null,"summary":"A comedy-drama series as seen through the eyes of three 11-year-old children from different backgrounds with episodes focusing upon the trials and tribulations of adolescence, and involved subjects such as dating, family, school, growing pains and friendship.","updated":1585366201,"_links":{"self":{"href":"https://api.tvmaze.com/shows/46948"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/1824845"}}}},{"score":0.8159303,"show":{"id":30774,"url":"https://www.tvmaze.com/shows/30774/friends","name":"Friends","type":"Scripted","language":"Japanese","genres":["Drama","Romance"],"status":"Ended","runtime":65,"averageRuntime":65,"premiered":"2002-02-04","ended":"2002-02-05","officialSite":"http://www.tbs.co.jp/friends21/","schedule":{"time":"21:00","days":["Monday","Tuesday"]},"rating":{"average":null},"weight":19,"network":{"id":159,"name":"TBS","country":{"name":"Japan","code":"JP","timezone":"Asia/Tokyo"},"officialSite":"https://www.tbs.co.jp/"},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":99721,"imdb":"tt0315608"},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/122/305714.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/122/305714.jpg"},"summary":"<p>Left alone on a trip to Hong Kong, Tomoko finds herself the victim of a purse-snatching. The police arrest the man she points out, but it turns out to be the wrong person: a young Korean man named Ji Hoon. Despite his anger and humiliation, he takes her out to dinner since she has lost all her money, and in return, she agrees to model for his amateur film. What follows is a magical and romantic two days. Upon returning to their respective countries, Tomoko must return to her nine-to-five job and Ji Hoon must resume studying to join the family business rather than pursuing his dream of becoming a film director. But soon the two begin to email each other and rekindle their relationship despite the distance and obstacles between them. Marking the very first time in television history that a drama has been co-produced between Japan and South Korea, the story shows us that love has no borders.</p>","updated":1635779876,"_links":{"self":{"href":"https://api.tvmaze.com/shows/30774"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/1260315"}}}},{"score":0.807294,"show":{"id":53703,"url":"https://www.tvmaze.com/shows/53703/friends","name":"Friends","type":"Variety","language":"Korean","genres":[],"status":"Ended","runtime":90,"averageRuntime":90,"premiered":"2021-02-17","ended":"2021-05-12","officialSite":"http://m.ichannela.com/program/menu/prm_menu2_mob.do?pgm_contents=050078&type=02&menuIndex=2&seqIndex=0&realCateCode=05007801&boardType=null&boardId=null&cateName=%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%20%EC%86%8C%EA%B0%9C","schedule":{"time":"21:10","days":["Wednesday"]},"rating":{"average":null},"weight":16,"network":{"id":538,"name":"Channel A","country":{"name":"Korea, Republic of","code":"KR","timezone":"Asia/Seoul"},"officialSite":null},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":396947,"imdb":null},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/297/743857.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/297/743857.jpg"},"summary":"<p>Reuniting old friends and introducing new acquaintances, cast members from Heart Signal 2 & 3 are back in a brand new variety series and sparks are sure to fly! Invited to spend a very special winter at Signal House, relationships between Oh Young Joo, Jung Jae Ho, Kim Do Gyun, Kim Jang Mi, Lee Ga Heun, Park Ji Hyun, Seo Min Jae, and Jung Eui Dong are sure to blossom. But which relationships will remain friendly and which will blossom into love? Follow the members through their daily lives and find out! Hosted by Super Junior's Kim Hee Chul and Shindong, Oh My Girl's Seunghee, and Lee Sang Min.</p>","updated":1668808710,"_links":{"self":{"href":"https://api.tvmaze.com/shows/53703"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/2090402"}}}},{"score":0.69863015,"show":{"id":47182,"url":"https://www.tvmaze.com/shows/47182/smiling-friends","name":"Smiling Friends","type":"Animation","language":"English","genres":["Comedy"],"status":"Running","runtime":15,"averageRuntime":15,"premiered":"2020-04-01","ended":null,"officialSite":"http://www.adultswim.com/videos/smiling-friends","schedule":{"time":"","days":["Sunday"]},"rating":{"average":null},"weight":91,"network":{"id":10,"name":"Adult Swim","country":{"name":"United States","code":"US","timezone":"America/New_York"},"officialSite":null},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":379403,"imdb":"tt12074628"},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/251/628722.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/251/628722.jpg"},"summary":"<p>A small company dedicated to bringing happiness to the world receives a simple request to help a woman's unhappy son smile again, but the job turns out to be more complicated than it seems.</p>","updated":1659887321,"_links":{"self":{"href":"https://api.tvmaze.com/shows/47182"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/2365336"}}}},{"score":0.6878882,"show":{"id":20474,"url":"https://www.tvmaze.com/shows/20474/angels-friends","name":"Angel's Friends","type":"Animation","language":"Italian","genres":["Adventure","Children","Fantasy"],"status":"Ended","runtime":15,"averageRuntime":15,"premiered":"2009-10-12","ended":"2012-04-29","officialSite":"http://www.angelsfriends.it","schedule":{"time":"","days":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"rating":{"average":null},"weight":69,"network":{"id":1272,"name":"Italia 1","country":{"name":"Italy","code":"IT","timezone":"Europe/Rome"},"officialSite":null},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":264933,"imdb":"tt1731708"},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/72/180985.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/72/180985.jpg"},"summary":"<p>Special school for the Angels is full of secrets! What happens if at the same table will be angels and devils? Raf, Uri, Sweet and Mickey - a company of angels. But to become a real team, they do not have a single person. Friends leave their homes and go down to the Earth in the \"Golden School\". They need to get the last \"missing percentage\", which will make their guardian angels at 100%. Their mission is to accompany selected earthlings in their daily adventures...</p>","updated":1573079445,"_links":{"self":{"href":"https://api.tvmaze.com/shows/20474"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/1382408"}}}},{"score":0.68657506,"show":{"id":65357,"url":"https://www.tvmaze.com/shows/65357/only-friends","name":"Only Friends","type":"Scripted","language":"Thai","genres":["Drama","Romance"],"status":"In Development","runtime":null,"averageRuntime":null,"premiered":null,"ended":null,"officialSite":"https://www.gmm-tv.com/home/","schedule":{"time":"","days":[]},"rating":{"average":null},"weight":66,"network":{"id":1095,"name":"GMM25","country":{"name":"Thailand","code":"TH","timezone":"Asia/Bangkok"},"officialSite":null},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":null,"imdb":null},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/431/1079406.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/431/1079406.jpg"},"summary":null,"updated":1669158203,"_links":{"self":{"href":"https://api.tvmaze.com/shows/65357"}}}},{"score":0.6837748,"show":{"id":11090,"url":"https://www.tvmaze.com/shows/11090/mutual-friends","name":"Mutual Friends","type":"Scripted","language":"English","genres":["Drama","Comedy"],"status":"Ended","runtime":60,"averageRuntime":60,"premiered":"2008-08-26","ended":"2008-09-30","officialSite":"http://www.bbc.co.uk/programmes/b00d98sz","schedule":{"time":"21:00","days":["Tuesday"]},"rating":{"average":null},"weight":65,"network":{"id":12,"name":"BBC One","country":{"name":"United Kingdom","code":"GB","timezone":"Europe/London"},"officialSite":"https://www.bbc.co.uk/bbcone"},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":18729,"thetvdb":82899,"imdb":"tt1062325"},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/37/93077.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/37/93077.jpg"},"summary":"<p>Martin has two best friends, Patrick and Carl, who couldn't be more different. One is an irresponsible, unreliable, feckless womaniser and the other is dead. Guess which one slept with his wife?Martin Grantham is happily married to Jen. They have a son Dan, a nice house, the works. One day his best friend Carl throws himself under a train, setting off a disastrous sequence of events that will change Martin's life forever…Into this mess steps Patrick, a friend from way back. Patrick is everything Martin is not – glib, self-confident, popular and pathologically immature. He's the last person Martin needs in his life right now. Or is he?</p>","updated":1555974558,"_links":{"self":{"href":"https://api.tvmaze.com/shows/11090"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/555093"}}}},{"score":0.68103445,"show":{"id":7403,"url":"https://www.tvmaze.com/shows/7403/battlefield-friends","name":"Battlefield Friends","type":"Animation","language":"English","genres":["Comedy","Adventure"],"status":"Ended","runtime":3,"averageRuntime":3,"premiered":"2012-03-20","ended":"2016-08-20","officialSite":"https://www.youtube.com/show/battlefieldfriends","schedule":{"time":"","days":[]},"rating":{"average":null},"weight":56,"network":null,"webChannel":{"id":21,"name":"YouTube","country":null,"officialSite":"https://www.youtube.com"},"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":262928,"imdb":"tt2354667"},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/27/68210.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/27/68210.jpg"},"summary":"<p><b>Battlefield Friends</b> is a series of animated shorts set in the game world of Battlefield 3 and Battlefield 4. It chronicles the misadventures of four friends and squadmembers, embodying the four soldier classes available in the games. The series often comically attacks/parodies player trends and game mechanics, such as spawnkilling, buggy bipods, Closet Colonels, etc.</p><p>The series follows four players-a medic, an engineer, a sniper, and a noob. The series incorporates surreal humor mixed with cartoon comedy gags.</p>","updated":1657875759,"_links":{"self":{"href":"https://api.tvmaze.com/shows/7403"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/903483"}}}},{"score":0.6768293,"show":{"id":45922,"url":"https://www.tvmaze.com/shows/45922/graceful-friends","name":"Graceful Friends","type":"Scripted","language":"Korean","genres":["Drama","Crime","Mystery"],"status":"Ended","runtime":80,"averageRuntime":80,"premiered":"2020-07-10","ended":"2020-09-05","officialSite":"http://tv.jtbc.joins.com/gracefulfriends","schedule":{"time":"22:50","days":["Friday","Saturday"]},"rating":{"average":null},"weight":55,"network":{"id":268,"name":"jTBC","country":{"name":"Korea, Republic of","code":"KR","timezone":"Asia/Seoul"},"officialSite":null},"webChannel":null,"dvdCountry":null,"externals":{"tvrage":null,"thetvdb":378806,"imdb":"tt12531492"},"image":{"medium":"https://static.tvmaze.com/uploads/images/medium_portrait/262/655331.jpg","original":"https://static.tvmaze.com/uploads/images/original_untouched/262/655331.jpg"},"summary":"<p><b>Graceful Friends</b> is a mystery drama about a murder that occurs in a new town inhabited by married couples in their 40s and follows the story of a group of middle-aged men after their peaceful everyday lives are disrupted.</p>","updated":1655183561,"_links":{"self":{"href":"https://api.tvmaze.com/shows/45922"},"previousepisode":{"href":"https://api.tvmaze.com/episodes/1914740"}}}}] </script>
just set the innerHtml to blank <body> <div class="searchBox"> <input id="TVShowName" type="search" placeholder="Search for a TV show..." /> <button id="search">Search</button> </div> <div class="TVShowInfo"></div> </div> </div> <script> const searchInput = document.getElementById("TVShowName"); const contentArea = document.querySelector(".TVShowInfo"); function searchShow(TVShow) { fetch(`https://api.tvmaze.com/search/shows?q=${TVShow}`) .then((response) => response.json()) .then((data) => { contentArea.innerHTML = ""; for (const value of data) { contentArea.insertAdjacentHTML( "beforeend", ` <div id="TVShow"> <center> <h1>${value.show.name}</h1> </center> </div>` ); // searchInput.value = ""; } }); } document.getElementById("search").onclick = function (e) { searchShow(searchInput.value); }; </script> </body>
Watir Random Popup
High all, I'm testing this e-commerce and I get this random popup (it's a div)that gets in the way of my scripts, given its random appereance I can't relly predict when it's going to show, otherwise I can easily interact with it, as it is a simple div, whenever I see it. It's there a way that can I catch this popup and do as I please whenever it dares to show? Thanks in advance <div class="fsrFloatingMid"><div class="fsrInvite"> <div class="fsrDialogs"> <div style="margin-left: 0px;" class="fsrDialog "> <div class="fsrLogos"> <img src="/_ui/desktop/common/foresee/sitelogo.gif" alt="" class="fsrSiteLogo"> <img src="/_ui/desktop/common/foresee/fsrlogo.gif" alt="Foresee" class="fsrCorpLogo"> </div> <h1 class="fsrHeading">We'd welcome your feedback!</h1> <p class="fsrBlurb">Some bullshit text</p> <p class="fsrSubBlurb">The survey is designed to measure your entire experience, please look for it at the <u>conclusion</u> of your visit.</p> <p class="fsrAttribution">This survey is conducted by an independent company, on behalf of the site you are visiting.</p> <div style="" class="fsrB"> <div class="fsrAcceptButtonContainer"> Yes, I'll give feedback<span class="hidden-accessible"> (this will launch a new window)</span> </div> <div class="fsrDeclineButtonContainer">No, thanks </div> </div> <div class="fsrFooter"> <img src="/_ui/desktop/common/foresee/truste.png" alt="TRUSTe verified" class="fsrTruste"> </div> </div> </div> ×<span class="hidden-accessible">Click to close.</span>
If this pop-up appears randomly then I think using the "protection proxy" design pattern would help most. The purpose of it is to execute a particular piece of code, in our example this: if browser.div(class: 'fsrDialogs').exists? browser.a(class: 'fsrCloseBtn').click end BEFORE any method on the "subject" ("subject" is the object we wrap inside the Proxy class, in our case it's the browser) is called. The Proxy design pattern is pretty straightforward to implement in Ruby, here's how we'd do it in your particular case: class WatirProxy attr_reader :subject def initialize(browser) #subject = browser end def method_missing(method, *args) puts "I am executing the code below before calling #{method} with args #{args}" if subject.div(class: 'fsrDialogs').exists? subject.a(class: 'fsrCloseBtn').click end subject.send(method, *args) end end You can remove the puts below method_missing in production, however, I'd recommend you keep it for now if you're not 100% clear on how the code below works. Let's try playing with it: browser = WatirProxy.new(Watir::Browser.new(:chrome)) # you can use ANY method on browser, although it's wrapped in a proxy browser.goto 'https://google.com' puts browser.text_field(name: 'q').exists? Ruby should output: I am executing the code below before calling goto with args ["https://google.com"] I am executing the code below before calling text_field with args [{:name=>"q"}] true # May change if google search box 'name' attribute changed to something other than 'q' in the future In your specific case, this pop-up is raising errors because the browser didn't expect it, now we make sure there's a check BEFORE ANY method on browser is called. A great book for reading about the Proxy design pattern (and some other useful ones in Ruby) is Design Patterns in Ruby by Russ Olsen.
#browser.link(class: "fsrCloseBtn").click if #browser.h1(class: "hsrHeading").visible? Something like this should be enough. Obviously, sub whatever you name your WebDriver instance for #browser. This clicks the close link if the dialog is visible and skips this step if the dialog is not there. My syntax might be a little wrong, so double check that. I'm used to wrapping all this in page-object, which would look like: page_class.close_dialog if page_class.dialog_header_element.visible?
Had same issue with Foresee survey, I got around it by adding while browser.text.include?("We'd welcome your feedback!") == false do browser.refresh sleep 1 end browser.link(:class => /declineButton/).click end to the first step after going to the page. It's not the best option but it deals with the Foresee because once you close the window you get a fsr cookie that prevents the survey from popping up again during that browser session. The "sleep 1" was added so chrome would slow down and look for the Foresee survey. Hope it helps.
Rails 4: Testing out AJAX .click and .load
Hi I am trying to display text from another html document with AJAX in my rails app. I just wrote this small piece of code because I'm trying to learn AJAX. Can someone please explain to me what's going wrong with this piece of code? Stepone.htm.erbl <div class="margin-top"> <div class="container"> <h1> Do you like Math or Science </h1> <br> <div class="row"> <div class="col-4"> <button id="math1-1"> Math </button> </div> <br> <div class="col-4"> <button> Science </button> </div> </div></div></div> <br><br><br><br><br><br><br> <script> $(document).ready(function(){ $("#math1-1").click(function(){ $("#math1").load("math_1.html"); }); }); </script> Math_1.html.erb <div class="margin-top"> <div class="container"> <h1> Do you like Math or Science </h1> <br> <div id="math1"> Math_1 </div> </div></div>
Because you're learning, let me give you some ideas: Ajax Ajax (Asynchronous Javascript And XML) is a type of functionality inside JQuery (it's pure XML Header Request / XHR in javascript). It basically sends a "pseudo-request" to an endpoint in your application, receiving & processing the response The beauty of ajax is its asynchronous nature (working independently of any processes) - meaning you can use it to send a request "out of scope" of the typical application flow: Typically used to create the appearance of providing the user with the ability to "interact" with the webpage (without it reloading), ajax has become prolific, not least due to JQuery's assimilation of the $.ajax() functionality into a single call In simple terms - Ajax provides you with the ability to load & process a request on your front-end. This means if you want to use it, you need to be able to firstly have a way to process the result, and then ensure you're able to manage the response (typically by amending your DOM) -- Structure Since this is posted in the Rails section, let me give you some ideas on how to correctly get Ajax working with Rails. You need several important elements: An endpoint A backend controller action A way to handle the response You first need an endpoint. Simply, this is a route which will direct your ajax request to a specific controller action. The route itself is not important (Ajax is literally just a way to send "pseudo" requests to your system). What is important is the action the route will lead you to: #config/routes.rb resources :your_controller do collection do get :birthdays end end #app/controllers/your_controller.rb Class YourController < ApplicationController respond_to :js, :json, :html, only: :birthdays def birthdays #birthdays = Model.where(birthday: Date.today) respond_with #birthdays end end This means that if you want to send an ajax request to the controller, you'll be able to do the following: #app/assets/javascripts/application.js $.ajax({ url: "/your_controller/birthdays", success: function(data) { $("#your_element").html(data); } }); -- Fix As mentioned by EasyCo, the answer for you is to make sure you have an element to append your new data to. This is relatively simple, but I also want to discuss the importance of keeping your javascript unobtrusive with you You should always put your javascript into the asset pipeline of Rails (IE /app/assets/javascripts/xxx.js). There are many reasons for this (DRY, Convention over Configuration), but the most important thing is to keep your application modular Modularity is what gives great applications a natural "flow" and structure, allowing you to use / reuse as many functions as you require throughout the app. It is for this reason why I highly recommend you include any javascript in the respective JS files - as these then act as dependencies for your browser-based pages So in essence, you'll want the following: #app/assets/javascripts/application.js $("#math1-1").on("click", function(){ $("#math1").get("/maths/1"); }); #app/views/maths/index.html.erb <%= link_to "1", math_path("1") %> <div id="math_1"> </div>
You need a DOM element with id="math1" in your Stepone.html.erb file. You're trying to load math_1.html but it can't find an element with ID of math1 in Stepone.html.erm. It therefore doesn't load math_1.html because it has nowhere to append the data. Change Stepone.html.erb to: <div class="margin-top"> <div class="container"> <h1> Do you like Math or Science </h1> <br> <div class="row"> <div class="col-4"> <button id="math1-1"> Math </button> </div> <br> <div class="col-4"> <button> Science </button> </div> </div></div></div> <br><br><br><br><br><br><br> <div id="math1"></div> <!-- AJAX will get loaded in this div --> <script> $(document).ready(function(){ $("#math1-1").click(function(){ $("#math1").load("math_1.html"); }); }); </script>
AngularJS access Data from Resource Query
I have a Jersey Rest Application which I d'like to access with a AngularJS application. I have defined the resource as follows: Service: angular.service('Wine', function ($resource) { return $resource('/myserver/rest/wines/:wineId', {}, { update: {method:'PUT'}, 'query': {method: 'GET', isArray: true} }); }); Controller: function WineListCtrl(Wine) { this.wines = Wine.query(); } In Firebug I can see the result of this GET-Request: {"wine":[{"country":"USA","description":"With hints of ginger and spice, this wine makes an excellent complement to light appetizer and dessert fare for a holiday gathering.","grapes":"Pinot Noir","id":"9","name":"BLOCK NINE","picture":"block_nine.jpg","region":"California","year":"2009"},{"country":"Argentina","description":"Solid notes of black currant blended with a light citrus make this wine an easy pour for varied palates.","grapes":"Pinot Gris","id":"11","name":"BODEGA LURTON","picture":"bodega_lurton.jpg","region":"Mendoza","year":"2011"},{"country":"France","description":"The aromas of fruit and spice give one a hint of the light drinkability of this lovely wine, which makes an excellent complement to fish dishes.","grapes":"Grenache / Syrah","id":"1","name":"CHATEAU DE SAINT COSME","picture":"saint_cosme.jpg","region":"Southern Rhone / Gigondas","year":"2009"},{"country":"France","description":"Though dense and chewy, this wine does not overpower with its finely balanced depth and structure. It is a truly luxurious experience for the\nsenses.","grapes":"Merlot","id":"7","name":"CHATEAU LE DOYENNE","picture":"le_doyenne.jpg","region":"Bordeaux","year":"2005"},{"country":"France","description":"The light golden color of this wine belies the bright flavor it holds. A true summer wine, it begs for a picnic lunch in a sun-soaked vineyard.","grapes":"Merlot","id":"8","name":"DOMAINE DU BOUSCAT","picture":"bouscat.jpg","region":"Bordeaux","year":"2009"},{"country":"USA","description":"Though subtle in its complexities, this wine is sure to please a wide range of enthusiasts. Notes of pomegranate will delight as the nutty finish completes the picture of a fine sipping experience.","grapes":"Pinot Noir","id":"10","name":"DOMAINE SERENE","picture":"domaine_serene.jpg","region":"Oregon","year":"2007"},{"country":"Spain","description":"A resurgence of interest in boutique vineyards has opened the door for this excellent foray into the dessert wine market. Light and bouncy, with a hint of black truffle, this wine will not fail to tickle the taste buds.","grapes":"Tempranillo","id":"2","name":"LAN RIOJA CRIANZA","picture":"lan_rioja.jpg","region":"Rioja","year":"2006"},{"country":"France","description":"Breaking the mold of the classics, this offering will surprise and undoubtedly get tongues wagging with the hints of coffee and tobacco in\nperfect alignment with more traditional notes. Breaking the mold of the classics, this offering will surprise and\nundoubtedly get tongues wagging with the hints of coffee and tobacco in\nperfect alignment with more traditional notes. Sure to please the late-night crowd with the slight jolt of adrenaline it brings.","grapes":"Chardonnay","id":"12","name":"LES MORIZOTTES","picture":"morizottes.jpg","region":"Burgundy","year":"2009"},{"country":"USA","description":"The cache of a fine Cabernet in ones wine cellar can now be replaced with a childishly playful wine bubbling over with tempting tastes of\nblack cherry and licorice. This is a taste sure to transport you back in time.","grapes":"Sauvignon Blanc","id":"3","name":"MARGERUM SYBARITE","picture":"margerum.jpg","region":"California Central Cosat","year":"2010"},{"country":"USA","description":"A one-two punch of black pepper and jalapeno will send your senses reeling, as the orange essence snaps you back to reality. Don't miss\nthis award-winning taste sensation.","grapes":"Syrah","id":"4","name":"OWEN ROE \"EX UMBRIS\"","picture":"ex_umbris.jpg","region":"Washington","year":"2009"},{"country":"USA","description":"One cannot doubt that this will be the wine served at the Hollywood award shows, because it has undeniable star power. Be the first to catch\nthe debut that everyone will be talking about tomorrow.","grapes":"Pinot Noir","id":"5","name":"REX HILL","picture":"rex_hill.jpg","region":"Oregon","year":"2009"},{"country":"Italy","description":"Though soft and rounded in texture, the body of this wine is full and rich and oh-so-appealing. This delivery is even more impressive when one takes note of the tender tannins that leave the taste buds wholly satisfied.","grapes":"Sangiovese Merlot","id":"6","name":"VITICCIO CLASSICO RISERVA","picture":"viticcio.jpg","region":"Tuscany","year":"2007"}]} In my html page I d'like to access the content as following: <ul ng:controller="WineListCtrl"> <li ng:repeat="wine in wines"> <a href='#/wines/{{ wine.id }}'>{{ wine.name }}</a> </li> </ul> Sadly there are no results showing up in the UI (although the JSON Result seems to be okay and there is no error on the Browser Console). If I make an alert like alert(this.wines.length) I get 0 as result. Would be great to get some help of you guys... Greets Marc
Your first problem is that you're assigning to this and not the scope. If you don't assign to the scope, your data won't be available for binding in the view. So inject the $scope into your controller and assign it the wines attribute: function WineListCtrl($scope, Wine) { $scope.wines = Wine.query(); } You have another problem though. The ngResource module expects the result of call to query to be an array, but you're actually returning an object: {wine: [an array of wines]} So unless you remove the key from the server-side response, your ng-repeat might have to look something like: <li ng-repeat="wine in wines.wine">...</li>
Condensing re-used HTML (with variations based on variables) via Javascript [closed]
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance. Closed 10 years ago. I've got a page that is made up of a container that has several component divs in it. There are dozens of these containers in the markup (a suite type and version) and I show/hide the appropriate ones based on selections the user makes via select boxes. The content of the component divs changes, but the HTML markup is essentially the same. The component HTML framework is: <div class="docs basicEdition720"> // 2nd class here is the suite type/version <div class="component" title=" /* component title here */ "> <p class="componentName"> /*component name here */ </p> <p class="componentType"> /*component type here */ </p> <p class="links"> /*component links here */ </p> </div> </div> The point here is that I have the "whizbang" component and it might occur in several different containers and it would have exactly the same content, so long as the version of the container is the same. When the version of the container changes, generally the only change the the whizbang component would be the links. For example, in the Basic Edition 720 suite type and version, the contents of the whizbang component would be exactly the same as the whizbang component in the Enterprise Edition 720 suite. Relationships: Title/Name The component title and name never change based on version. They concretely correlate directly to each other. If 'A', then 'B'. Type The component type occasionally changes based on the VERSION of the component name we're using. The "bojangle" component might be type "admin" for 7.2.0, but might be type "user" for version 7.0.4. If 'A' and '1', then 'B'. If 'A' and '2', then 'C'. Sometimes the type concretely correlates to the name, as in, The "gadget" component ALWAYS has the type "reference". Links The links always change based on the version of the component. Objective: I'd like to only update the links for different component versions ONE time in the document, not the dozen or so I am currently doing. I'd like the javascript to churn out the containers automatically based on the known suite type and version. I can give it a framework to know which components belong where, such as: <div class="docs basicEdition720"> // Here we have the basic edition of the <div class="comp gadget"> // suite, version 7.2.0. That means I know <div class="comp bojangle"> // we have the gadget, bojangle, widget, <div class="comp widget"> // and gizmo components. <div class="comp gizmo"> </div> <div class="docs basicEdition704"> // Now we have the basic edition suite, <div class="comp gadget"> // version 7.0.4. Knowing that, I know we <div class="comp gizmo"> // only have the gadget, gizmo,and whatsit <div class="comp whatsit"> // components. </div> <div class="docs enterpriseEdition720"> // Now we have the enterprise edition <div class="comp gadget"> // suite, version 7.2.0. Hey, looks <div class="comp bojangle"> // pretty much the same as the basic <div class="comp widget"> // edition of the same version... <div class="comp gizmo"> </div> <div class="docs enterpriseEdition704"> // Ditto for enterprise suite v7.0.4. <div class="comp gadget"> <div class="comp gizmo"> <div class="comp whatsit"> </div> /* more suites and versions */ Or if it's better to handle the versioning all in JS, that's fine too. I've written so much basic JS that DOES NOT accomplish my objectives and I'm so bad with JS that I hesitate to give you any kind head-start/jsFiddle. Basically, it should use the HTML framework and fill in the gaps based on variables and the suite version it knows it is in. So far I've been using stuff like var gadgetName = " long name here "; var bojangleName = " long name here "; var gadgetLink720 = " version 720 link here"; var bojangleLink720 = " version 720 link here"; var gadgetTitle = " Gadget is a thingie that does..."; var bojangleTitle = " Bojangle is this thing that does..."; $(this).html("<div class=\"component\" title=\"" + myTitle + "\">\ <p class=\"componentName\">" + myName +"</p>\ <p class=\"componentType\">Setup Guide</p>\ <p class=\"links\">HTML PDF</p>\ </div>"); }); but have been pretty unsuccessful. NOTE: That's not the best example of what I've accomplished, I've actually (at one point) had it reading what the parent div class was to know what version to automatically throw in, etc. TL;DR "WTF dude?! This is thing is huge! You are as stupid as you are ugly." I know, I'm sorry. I don't know if I can make it more concise than that. The TL;DR is: "Gee, I have a page that works, but I'm reusing the same content over and over and over. Every time we have a new release, I should just update the dozens of links manually like a good peon, instead of scripting a single-source solution. Ignore me." :-(
Mustache is one of the best framework this You can check the demo here
Handlebars will do this for you. The basic idea is that you can substitute JavaScript variables into the HTML DOM using templates like this: <p>{{hello}}</p> It also allows for basic looping and logic. A fiddle to your question is here: http://jsfiddle.net/Yk43x/ For more complex templating, including bindings (so your templates update as your JavaScript model does), I'd recommend Knockout. EmberJS, which uses Handlebars, and Google Angular also enable templating (and bindings), as well as a lot more.