I'm running Meteor with Semantic UI as a framework .
I've got my main page on which I load X detail cards who all come from the same data source. All the detail cards have buttons, for example trash to remove the card.
I'm confirming actions on the buttons through modals.
I've got all of my modals in a separate template called modals.
From my main page I load my modals:
{{>modals}}
Inside my modals template I've got:
<template name="modals">
<div id="takeModal" class="ui modal">
{{#with data}}
<div class="ui header">
//HEADER
</div>
<div class="ui content">
// DATA USAGE IN TEMPLATE
{{city}}</td>
</div>
</div>
</template>
Above example is commented with // and just a fraction of the real thing.
The problem I'm running into is that I'm using the buttons on said card to call for the modal. The button eventhandler looks like:
Template.availablCard.events({
'click #checkmark': function () {
Session.set('data', this);
$('#takeModal').modal('show');
}
....
and the modal template has a helper:
Template.modals.helpers({
data: function () {
return Session.get('data');
}});
The problem I am facing is that the modals never function properly the first time because a click hasn't been registered yet and Session.data hasn't been set yet.
Is there a way to initialize the modals so they get loaded into the DOM, but still give them a data context?
ps. I've chosen this approach so I don't have to give every card it's own modal.
Related
I am building an app using HTML, CSS and vanilla JS to help learn my way around the languages and I have been stuck on a problem for a while.
Basically I have an index.html page that populates with football fixtures when a button is clicked. This works fine.
Then, when a certain fixture button is clicked, I want to pull specific data for that specific fixture and display it on a different page when loaded. The button click loads a new html page, but then should populate that page with the relevant fixture data.
Through lots of trial and error, only part of the function works. There is quite a lot of code from between HTML and JS so I don't want to share too much to make this more complex, as I am sure I am probably missing something simple.
But, here is the code that picks up the unique fixture id from the fixture card that is clicked on the index.html page.
const matchButton = document.querySelectorAll(".match-button");
for (i = 0; i < matchButton.length; i++) {
matchButton[i].addEventListener("click", (e) => {
let matchID = localStorage.setItem("matchID", e.target.id);
stats
.getFixture(e.target.id)
.then((fixtureData) => {
updateQuizMatchData(fixtureData);
})
.catch((err) => {
console.log(err);
});
document.location.href = "/quiz.html";
});
}
};
Originally, I did not store anything in localStorage, I just tried to call the function that makes an API call from the id directly. But the function doesn't seem to fire. it seems to break at setting the localStorage part. Is this because of the page load to a new page?
I stored the id in localStorage thinking that I could pull from that via another js file attached to the quiz.html page. As you can probably see, I am overcomplicating things maybe?
Anyhow, this is code above is meant to load the quiz.html page and then display the specific fixture related data from the fixture button that is clicked.
The code fires and updates localStorage and loads the quiz.html page. So I know it works to that point. But the other code does not fire. The other code that is meant to fire is an API call, followed then by this to update the quiz.html page dynamically...(not sure if this code is relevant to the issue I am seeing, as the API function call is not being fired either, which is why this below may not fire)
const updateQuizMatchData = (fixtureData) => {
console.log(fixtureData);
let date = "11-11-2001";
console.log(date);
teams.innerHTML = `
<div class="home-team m-4 pl-6">
<img
class="team-badge w-40 h-40"
src="${fixtureData.teams.home.logo}"
alt="home-team"
/>
<p
class="home-score text-center text-6xl m-6 bg-red-500 rounded-lg text-white p-6 shadow-xl"
>
${fixtureData.goals.home}
</p>
</div>
<div class="vs-text pt-20">
<p class="text-center text-6xl font-extrabold p-4">VS</p>
<p class="location text-center">${fixtureData.fixture.venue.name}</p>
<p class="date text-center">${date}</p>
</div>
<!-- Away team detail section -->
<div class="away-team m-4 pr-6">
<img
class="team-badge w-40 h-40"
src="${fixtureData.teams.away.logo}"
alt="away-team"
/>
<p
class="away-score text-center text-6xl m-6 bg-lime-500 rounded-lg text-white p-6 shadow-xl"
>
${fixtureData.goals.away}
</p>
</div>
`;
};
I know this doesnt fire because the console does not log the data at the top. All that happens is my quiz.html page loads my dummy content.
I have been battling this for a while and getting frustrated. What am I missing? Or not doing correctly?
I have tried moving code onto a separate js file but this has no impact. I also have attempted to fire the above function via window.load, but this doesn't fire it either. The introduction of localStorage was also to see if I could just fire a function from page load using localStorage ID that I set from button click as the parameter in the API call I make to get the specific fixture data. I hope this makes sense.
What am I missing?
How can I update the quiz.html from a specific fixture button that is clicked?
We're migrating a legacy front-end to VueJS 2. So far, it's using HTML and JS to fetch modals and inject those in the DOM. We'd like to migrate one specific (and very simple) modal.
That modal is a reset password modal. It is, for now, fetched from the login modal using the legacy logic (which is a native onclick call). We'd like the login modal to interact with VueJS and display the reset password modal.
But the problem is, when we originally load the HTML, the login modal is not in the DOM (until we display it). So it seems VueJS event handlers won't trigger at all.
How can I use VueJS in this login modal which is injected after the page is loaded ?
Here's some pseudo code to illustrate my question :
# OLD
// HTML
<!-- Button displaying the login modal -->
<button onclick="displayModal('login')">Log in</button>
<!-- Login modal (loaded only when user clicks the button) -->
<div>
<h1>Login</h1>
<button onclick="displayModal('reset-password')">Reset password</button>
</div>
// Native JS
function displayModal(name) {
var result = fetchModal(name);
removeCurrentModal();
injectModal(result);
}
# NEW
// HTML
<!-- Login modal (loaded only when user clicks the button) -->
<div>
<h1>Login</h1>
<!-- This doesn't do anything even though it works when it exists on page load instead -->
<button #click="modals.passwordReset.show = true">Reset password</button>
</div>
I am new to coding and new to Meteor so have made my fair share of blunders along the way - so far I've managed to fix them but this one's got me well and truly stumped.
I'm using packery to layout some divs containing information on projects that contain a number of divs with information on tasks within each project. So far so good, the layout works nicely when the template first loads.
When I add a new task to one of the projects, which gets added to the Tasks collection, the layout redraws but that project, which is now 1 row longer, overlaps the next project down the layout.
I've re-used the answer from here (MeteorJS and Packery layout doesn't re-render when collection is updated) but this doesn't work for the redraw.
projects.html:
<template name="projects">
<div class='grid' id='allProjects'>
{{#each project}}
<div class='grid-item' id='project'>
<div project content goes in here>
</div>
{{#each task}}
<div id='task'>
<div task content goes in here>
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
</template>
projects.js:
Template.projects.onRendered(function(){
this.find('.grid')._uihooks = {
insertElement: function(node, next){
triggerPackeryLayout();
$('.grid').append(node);
$('.grid').packery('appended', node);
}
};
});
function triggerPackeryLayout(){
var $grid = $('.grid');
$grid.packery({
itemSelector: '.grid-item'
});
}
I think it's something to do with timing of when the layout is redrawn because when I add another task to the project, which uses a modal window, the layout corrects itself as the modal opens.
Do I need to delay the layout to allow the new Tasks item to load from the collection?
I'm quite new to javascript in general. I've spent the past couple of weeks building a front end with Angular.js.
I have a number of directives I've defined that sit on my page, Angular has been great for this.
Here's what my main page looks like:
<body class="body" ng-controller="OverviewController as overview" font-size:1em>
<sidebar-menu ng-controller="PanelController as panel"></sidebar-menu>
<div id="content" >
<div>
<div class="list-group">
<div class="list-group-item" ng-repeat="site in overview.sites" ng-click="">
<div class="item-heading">
<h3>{{site.name}}</h3>
<p>Address: {{site.address}}</p>
Click Here
</div>
<installationsite-panels ng-controller="PanelController as panel"></installationsite-panels>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('.paulund_modal').paulund_modal_box();
});
</script>
</body>
Note the javascript function to call a modal box at the bottom, using this tutorial.
I've spent the past few days trying different tutorials to get modals to work in my webapp, but with no success. I think it's down to my lack of understanding of Angular and Javascript in general.
In any case, I've managed to get this tutorial to work using JQuery, and when I click on the link, the modal opens as expected.
However, I don't want to call this modal from here. I want to call it from a directive that's embedded within the <installationsite-panels> directive in the above code, which looks like this (just a single section shown here):
Device Statuses
<div>
<div class="device-icon-group">
<div class="device-type1-icons" ng-click="panel.showDevices(3)" ng-show="showtype1Red"><img src="img/type1red.png" style="width:50%; height:50%;"/></div>
<div class="device-type2-icons" ng-click="panel.showDevices(3)" ng-show="showType2Red"><img src="img/type2red.png" style="width:50%; height:50%;" /></div>
</div>
<div class="service" ng-click="panel.showDevices(3)" ng-show="showService">
<b>{{panel.getServiceDeviceCount()}} device needs servicing</b>
</div>
<div ng-show="showServiceList">
<device-list-service></device-list-service>
</div>
</div>
The directive <device-list-service> shows a list of items like so:
<div ng-controller="DevicesController as deviceList" font-size:1em >
<div id="device-list-group">
<div id="device-list-group-item" ng-click="" ng-repeat="device in deviceList.devicesService">
<div ng-class="device.status"><img src="{{(device.type == 'type1') ? 'img/type1white.png' : 'img/type2white.png'}}"> </div>
<div class="device-params">
<b>ID: </b> {{device.id}}<br />
<b>Type: </b> {{device.type}}
</div>
<div class="device-params">
<b>Location: </b> {{device.location}}<br />
<b>Action: </b> {{device.action}} <br />
</div>
</div>
</div>
</div>
I want to show the modal when the user clicks on one of the list-group-item 's, and display some data relating to that item.
The modal works fine from the top level in the main app, but I cannot call it from within any of the directives. How can I do this?
Is it possible, or do I need to scrap my JQuery modal and do it the Angular way, which hasn't worked for me for the past few attempts.
Don't use jquery modals. You can, but you shouldn't.
Instead, I recommend using Angular UI, which has a pretty usable modal implementation: https://angular-ui.github.io/
Second alternative: if you don't like Angular UI, then use AngularJS + Bootstrap, and create your own custom directives
Third alternative: Use jQuery.
If you still want to go with the 3rd alternative, despite my advice against it, then here is how you do it:
var app = angular.module('app', []);
app.directive('modal', function($http, $timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
$timeout(function() {
element.paulund_modal_box();
}, 0, false);
}
};
});
Usage:
<div modal></div>
Some explanation is needed here.
Why is the $timeout service necessary? jQuery plugins often require the DOM to be fully loaded in order to work properly. That is why most jQuery plugins are wrapped inside of a $(document).ready block. In AngularJS there is no concept of DOM ready, and there is no easy way in AngularJS to hook into the event. However, there is a well-known hack, which is to use the $timeout service. In Angular there are three phases:
1. compile - Angular walks the DOM tree looking for directives
2. Link - Angular calls the link function for each directive to setup watch handlers.
3. Render - Angular updates the views
Using $timeout within the Link function queues the $timeout function to be executed until after the current closure is done executing. It just so happens that the Render phase is within the current closure's scope of execution. Hence, the $timeout function will execute after the render phase, when the DOM has been loaded.
Mixing JQuery and Angular in that way is maybe a little messy, but sometimes you do want to use a well-built component. You could try to find a similar modal in Angular - angular-modal - or you could try and build the component into your Angular directive itself - jQuery Plugins in AngularJS
I am using AngularUI Bootstrap accordion and I need it to be open depending on data, coming from a $http request, here's my markup:
<div data-accordion>
<div data-accordion-group data-heading="Group 1" is-open="!$parent.toggle">
<!-- random content -->
</div>
<div data-accordion-group data-heading="Group 2" is-open="$parent.toggle">
<!-- random content -->
</div>
</div>
And here's an example of the data coming in:
randomService.getdata(id).then(function(response) {
randomService.toggle = response.data;
$scope.toggle = randomService.toggle;
});
The problem with this setup is that if I click the header to open/close, the variable gets toggled as well(I want to avoid that). It can be avoided by changing the is-open to !( !!($parent.toggle) and !!($parent.toggle), respectively.
However the problem remains: When $scope.toggle is false the proper accordion is open, when it's true both accordions are closed.
One solution could be to use two scope variables open1 and open2, so you can always set the right one to true when the data comes in, no matter what state they are in. This should also work if the accordion has the attribute close-others set to true.