Why doesn't this div trigger the assigned onclick() function? - javascript

I have a Django project in which I have this HTML code in my template:
<div class="upper_bar">
<div></div>
<div class="stats_bar">{{ stage1_total }} recibidos, {{ stage2_total }} en preparaciĆ³n, {{ stage3_total }} en camino y {{ stage4_total }} entregados</div>
<div id="createButton" onclick="myFunction()"><i class="fas fa-plus-circle" style="font-size:48px;"></i></div>
</div>
In my scripts tag, I have this:
function myFunction()
{
alert('Function...');
}
I previously had this code instead in my scripts:
document.getElementById('createButton').addEventListener('click',
function()
{
alert('message...');
document.querySelector('.bg-modal').style.display = 'flex';
}
);
But it didn't work either. Does someone know why is the div called 'createButton' not working? I don't want to use a button since I'd like to only see the icon, or is there another way to just see the icon in a way that works and calls the function?

Your div element that is the target is empty - not even blank space. Adding some content seems to work fine: https://jsfiddle.net/0fkyp5nj/
HTML:
<div class="upper_bar">
<div></div>
<div class="stats_bar">{{ stage1_total }} recibidos, {{ stage2_total }} en preparaciĆ³n, {{ stage3_total }} en camino y {{ stage4_total }} entregados</div>
<div id="createButton" onclick="myFunction()"><i class="fas fa-plus-circle" style="font-size:48px;"></i>test 123</div>
</div>
JavaScript:
function myFunction()
{
alert('Function...');
}

Related

Can you access component slot data from parent

I am trying to get the rangeText data into div outside of the component block for https://innologica.github.io/vue2-daterange-picker/advanced/#slots-demo but it only seems to appear when used in a slot.
I am trying to update the selectDateButtonText text after user selects dates.
Many thanks
<template>
<div v-click-outside="hideCalendarDropdown" class="select-dates">
<button #click="filterCalendarIsActive = !filterCalendarIsActive" :class="{ 'is-active': filterCalendarIsActive }" class="select-dates__button fw-lt-sm">{{ selectDateButtonText }}</button>
<div :class="{ 'is-active': filterCalendarIsActive }" class="calendar-wrapper">
<date-range-picker #finish-selection="datesSelected()"
v-model="dateRange"
:minDate="minDate"
:maxDate="null"
:singleDatePicker="singleDatePicker"
:opens="opens"
:showDropdowns="showDropdowns"
:autoApply="autoApply"
:ranges="ranges"
>
<div slot="footer" slot-scope="data" class="date-range-picker-footer">
{{ data.rangeText }}
<button class="clear-dates" #click="clearDate()" type="button"> Clear </button>
</div>
</date-range-picker>
</div>
</div>
</template>
Got it.
Had to $refs the component
datesSelected() {
this.selectDateButtonText = this.$refs['picker'].rangeText;
}

Vanilla Javascript: How to add multiple event listeners to buttons which are dynamically created with same class in django?

I am currently working on a project 4 for CS50w - Network. One of the tasks is to add an edit posts button (for editing the posts that logged in user (only owner) created), which does this async. Since for storing posts I'm using Django Models, I'm using Django (and it's template capabilities) to display all the posts to users too, and an edit button (if user is the creator of the post too). I'm displaying all the posts in a div. This means that the button for editing is also a part of this div... meaning that I can give it only single class or id for referencing, but then I don't know how to distinguish between them, and how to know which one (from which post) is clicked so that I can edit that post and not the first one on which the JS in DOM comes up... Anyways here's the code:
HTML in Django:
{% for post in posts %}
<div class="post">
{{ post.user }}
<p>{{ post.content }}</p>
<p>{{ post.created }}</p>
{% if user.is_authenticated and user == post.user %}
<button class="edit_post_button">Edit Post</button>
{% endif %}
</div>
<div class="edit_post" style="display: none;">
{{ post.user }}
<textarea rows=3 cols=20>{{ post.content }}</textarea>
<p>{{ post.created }}</p>
<button class="save_edit_post_button">Save</button>
</div>
{% endfor %}
and here is the little JS that I wrote that doesn't work (I'm just starting to learn it, and would like to finish this project with vanilla JS):
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.edit_post_button').forEach(edit_post_button => {
edit_post_button.addEventListener('click', edit_post);
})
});
function edit_post(event) {
document.querySelector('.post').style.display = 'none';
document.querySelector('edit_post').style.display = 'block';
}
Delegation is the answer
Note you forgot a dot in document.querySelector('edit_post')
window.addEventListener('load', function() {
document.getElementById('postContainer').addEventListener('click', function(e) {
const tgt = e.target.closest('.edit_post_button')
if (tgt) {
const postDiv = tgt.closest('.postDiv')
postDiv.querySelector('.post').hidden = true
postDiv.querySelector('.edit_post').hidden = false
console.log(tgt.dataset.id); // if needed
}
})
})
<div id="postContainer">
<div class="postDiv">
<div class="post">
user 1
<p>Post 1 </p>
<p>yesterday</p>
<button class="edit_post_button" data-id="postId1">Edit Post</button>
</div>
<div class="edit_post" hidden>
user 1
<textarea rows=3 cols=20>Post 1</textarea>
<p>Yesterday</p>
<button class="save_edit_post_button">Save</button>
</div>
</div>
<div class="postDiv">
<div class="post">
user 2
<p>Post 2 </p>
<p>yesterday</p>
<button class="edit_post_button" data-id="postId2">Edit Post</button>
</div>
<div class="edit_post" hidden>
user 2
<textarea rows=3 cols=20>Post 2</textarea>
<p>Yesterday</p>
<button class="save_edit_post_button">Save</button>
</div>
</div>
</div>

how to add :key in v-for with multiple divs

I want to make v-for loop without any html element so I decided to use <template as parent. I don't know to assign :key for this loop. I can't assign it to template and to every div inside loop. Any ideas?
<template
v-for="{ id, text, option, percentage, value } in reports"
>
<div class="table-row__index">
{{ id }}
</div>
<div class="table-row__title">
<p>{{ text }} - <strong>{{ option }}</strong></p>
</div>
<div class="table-row__info">
{{ percentage }}%
</div>
<div class="table-row__info">
{{ value }}
</div>
</template>
As a good practice we should always have a parent element inside. But due to your constraints, it's okay to use for loop on template as given in official docs
https://v2.vuejs.org/v2/guide/list.html#v-for-on-a-lt-template-gt
In this case, any keys have to be added to child elements/components and this is what officially recommended.
See this example and please add keys to your div's inside template.
new Vue({
el: '#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="n in 5">
<span :key="'number' + n">{{ n }}</span>
<span :key="'dot' + n">. </span>
</template>
</div>
you just can't have the for loop in your template. The for loop directive is only allowed to be inside the first child component ( or root component) inside your template.
Here is an example of how you can render your loop:
<template>
<div class="cant-have-for-loop-this-is-the-root-component">
<div v-for="{ id, text, option, percentage, value } in reports" :key="{id}">
<div class="table-row__index">
{{ id }}
</div>
<div class="table-row__title">
<p> {{ text }} - <strong>{{ option }}</strong></p>
</div>
<div class="table-row__info">
{{ percentage }}%
</div>
<div class="table-row__info">
{{ value }}
</div>
</div>
</div>
</template>
This runs soomthly, and with no hesitations. And renders with no styling as this screenshots depicts:
Hope this answers what you want to achieve.

ng-click to affect only the element it is inside

I am using ng-repeat to generate some elements...
<div class="form-block" ng-repeat="form in formblock | filter:dateFilter">
<div ng-click="showResults()" ng-if="repeat == true" class="drop">{{ form.form_name }} <span class="caret"></span></div>
<div ng-show="results" class="formURL">{{ form.url }}</div>
<div ng-show="results" class="formCount">{{ form.count }}</div>
<div ng-show="results" class="formSubmit">{{ form.submit }}</div>
</div>
As you can see, ng-click="showResults()" toggles the display of the other elements. The problem is, I only want the ng-click to toggle the elements inside the same container, not toggle all elements.
In short, I only want the click event to affect the elements in the same container that the function is called, how can I do this?
this is showResults in my controller...
$scope.showResults = function(){
return ($scope.results ? $scope.results=false : $scope.results=true)
}
ng-repeat provides you with a special variable (unless you already have an identfier): $index.
Using this, you can store (instead of a single boolean value) an object $index => toggleState in your angular code:
$scope.hiddenHeroes = {};
$scope.toggleHero = function (idx) {
$scope.hiddenHeroes[idx] = !$scope.hiddenHeroes[idx];
}
And in your HTML:
<div ng-repeat="hero in heroes">
<div class="hero" ng-hide="hiddenHeroes[$index]">
<h1>
{{hero}}
</h1>
All you want to know about {{hero}}!
<br />
</div>
<a ng-click="toggleHero($index)">Toggle {{hero}}</a>
</div>
See it live on jsfiddle.net!
You can use $index to index item/containers and show the corresponding results:
<div ng-click="showResults($index)" ng-if="repeat == true" class="drop">{{ form.form_name }} <span class="caret"></span></div>
<div ng-show="results[$index]" class="formURL">{{ form.url }}</div>
<div ng-show="results[$index]" class="formCount">{{ form.count }}</div>
<div ng-show="results[$index]" class="formSubmit">{{ form.submit }}</div>
And your function
$scope.showResults = function(index){
return ($scope.results[index] ? $scope.results[index]=false : $scope.results[index]=true)
}

Assign value to dynamically created scope variables

I'm trying to create a means to toggle dynamically created rows of information. I've tried using ng-init, and then passing it to a function, but I'm screwing up somewhere and I can't seem to wrap my head around how or if this is possible. The gap, I believe, is in getting the concatenated scope variable to be referenced elsewhere. I'm using Bootstrap 3 and AngularJS 1.5.
The HTML:
<div class="row" data-ng-repeat="equipment in task.equipment">
<div class="col-md-12">
<h4 class="green-text">
{{ equipment.equipId }}
<small class="green-text">
<i class="glyphicon"
data-ng-class="{'glyphicon-triangle-bottom': field{{ $index }}, 'glyphicon-triangle-right': !field{{ $index }}}"
data-ng-init="equipment['field' + $index] = true"
data-ng-click="toggleTaskEquip('field{{ $index }}')">
field{{ $index }}: I WANT THIS TO WORK</i>
</small>
</h4>
</div>
<div data-ng-show="field{{ $index }}">
...stuff here...
</div>
</div>
The JS:
$scope.toggleTaskEquip = function(toggleBool)
{
if (toggleBool === true)
$scope.isTaskEquipOpen = false;
else if (toggleBool === false)
$scope.isTaskEquipOpen = true;
};
If I understand the problem correctly, you want to be able to toggle the boolean created in the ng-init with a click.
I think you need this:
<div class="container-fluid">
<div ng-controller="MyCtrl">
<div class="row" data-ng-repeat="equipment in task.equipment">
<div class="col-md-12">
<h4 class="green-text">
{{equipment.equipId}}
<small class="green-text">
<i class="glyphicon"
data-ng-class="{'glyphicon-triangle-bottom': isVisible, 'glyphicon-triangle-right': !isVisible}"
data-ng-init="isVisible = true"
data-ng-click="isVisible = !isVisible">I WANT THIS TO WORK</i>
</small>
</h4>
</div>
<div data-ng-show="isVisible">
...stuff here...
</div>
</div>
</div>
</div>
You don't even need the function toggleTaskEquip on the $scope.
JSFiddle here.
ng-repeat creates a new scope for each template instance, so you can just create a separate isVisible for each equipment with isVisible = true in the ng-init.

Categories

Resources