Dynamically adding Semantic UI modals with SilverStripe - modal-dialog

I'm having a hard time trying to connect SUI modal with SilverStripe to generate them dynamically.
I want to achieve something like this:
I have button (attach events) to trigger modal with some content. I wanted to loop that elements (GridField) to generate everything dynamically. But the only thing I can achieve is multiple modals with the same "trigger class" and it doesn't matter which button I have clicked (first, last or whatever). I only have one modal (the last in hierarchy). Without SUI the solution is easy - put "this" to fetch the closest element and I can have as many different modals as I want, but SUI seems to complicate things.
I think the best solution will be to generate a class/id with SilverStripe and pass it to the JavaScript to use with modal or use one class for every modal and to "somehow inform" that this button triggers this modal.
Basically I need one code snippet to handle many modals, not many snippets to handle many modals. I hope it's clear enough what the the problem is.
Here is my code:
HTML/SS
(without specific SilverStripe tags)
<% loop SomeName %>
<div class="job-offers">
<a class="ui right floated button job-application">Click here</a>
</div>
<div class="ui basic modal job-application">
<div class="job-application-sheet">
(...)
<div class="job-application-sheet-content">
<div class="ui grid">
(...)
<div class="ui center aligned container job-application-action">
<p>Lorem ipsum</p>
<button class="ui primary button">Click here</button>
</div>
</div>
</div>
</div>
</div>
<% end_loop %>
JavaScript
$('.ui.basic.modal.job-application')
.modal({
autofocus : false,
observeChanges: true
})
.modal('attach events', '.job-application', 'show');
As you can see "job-application" class is a trigger for modal, so is this possible to change it to "(this)" so I don't have to write "specific" class for each button/modal. Or maybe there is a different/easier solution?

first i generated a data-type attribute for each of my elements that are going to display a modal when they are clicked, and in send as a local the same index to the modal this way:
<% #relateds_array.each.with_index do |related,i| %>
<div class="card custom" data-id="<%=i%>">
<%= render partial: 'my_modal', locals: {index: i} %>
</div>
<% end %>
the i put the modal in the partial that i called my_modal for this example and used the index that i sent as a local to create an unique id for each my modals, like this:
<div class="ui modal" id="modal-<%=index%>">
<p>blabla things inside this modal.</p>
</div>
and then with javascript, simply get the data-id of the element clicked and select the element that contain the id for that data-id, like this:
$('.element_that_you_want_to_open_moda_on_click').click(function(event){
var card_clicked = $(this).attr('data-id');
$('#modal-' + card_clicked).modal('show');
});
Hope this was useful for you.
Note that i used Ruby on Rails for this example, but the behaviour that you should use should be something similar to this, no matter what framework you use.

Answer based on Sebastian's solution. I did some minor tweaks to meet my needs, like I've used ID variable to automatically get DataObject ID which is generated dynamically.
Basically to dynamically add Semantic UI (SUI) modal in SilverStripe, first you should add "data-id" in a modal trigger, for example:
Template.ss
<a class="ui button custom-trigger" data-id="my-item-$ID">Click here</a>
then inside modal container add an "id" tag, for example:
<div id="modal-my-item-$ID" class="ui basic modal">
(...)
</div>
Finally in JavaScript file:
$('.custom-trigger').click(function(event){
var triggerItem = $(this).attr('data-id');
$('#modal-' + triggerItem).modal('show');
});
I meet problem with SUI autofocus, so after a modal opens, screen went to the bottom and button placed there was highlighted.
I tweaked original snippet adding SUI settings:
$('.custom-trigger').click(function(event){
var triggerItem = $(this).attr('data-id');
$('.ui.modal')
.modal({
autofocus: false,
observeChanges: true
})
$('#modal-' + triggerItem).modal('show');
});
If someone wants to write "data-id trigger" manually using fields in CMS, then change $ID to $SomeField variable. Then normally add that field in .php file and in Page Controller add something like this:
public function init() {
parent::init();
Requirements::javascriptTemplate($this->ThemeDir().'/js/script.js', array(
'SomeField' => $this->SomeField
));
}
Hope this helps someone.

Related

Is it possible to implement dynamic form input rows (adding new row by clicking on Add) with Handlebars and Meteor?

I'm getting my hands dirty with Meteor, and I wanted to port this AngularJS app (http://simplydo.com/projector/) over as an exercise.
I'm having difficulty implementing adding dynamic input form rows to sections using Handlebars, and I've found no documentation anywhere that documents if this possible. It's a snap in Angular using ng-repeat, but I want to confirm if this is something that is possible in Handlebars or whether I need to use Jquery in order to achieve this.
Thanks in advance.
It's just as easy in Meteor
all you have to do is repeat the rows with {{#each rowData}} and have a button that adds a document to the collection. Here is an example:
In this template the rows for a page are shown. In order to add a row, the user has to click on the add image. The template is :
<template name="page">
{{#with page}}
<h3>{{title}}</h3>
{{#each rows}}
<div class="row-fluid page-row {{#if isSelected this}}selected-row{{/if}}">
... page content here
</div>
{{/each}}
{{/with}}
<div class="btn-toolbar">
<div class="pull-right">
<a id="add-row" href="#" data-toggle="tooltip" title="{{lbl 'add-page'}}">
<img src="/images/add.png" class="asset-icon"/>
</a>
<img src="/images/separator.png" class="asset-icon"/>
<a id="delete-row" href="#" data-toggle="tooltip" title="{{lbl 'delete-page'}}">
<img src="/images/delete.png" class="asset-icon"/>
</a>
</div>
</div>
</template>
the helpers for this template are:
Template.page.page = function () {
return Session.get("selected-page");
}
in order to add a page the click event for the add button is implemented:
"click #add-row": function (evt, template) {
var page = Session.get("selected-page");
Pages.update({_id: page._id}, ... add a new row here ...)
}
because the whole thing is reactive, the list of rows will redraw after the update on the Pages collection.

jquery selector for different instances of the same class

I don't know if the title is all apt...... but here is my situation....i have a class called dropper and another class drop_list...these two are sub-classes of the class drop_head, the drop_list has to drop down whenever the dropper is clicked...
<div class="drop_head">
<div class="dropper"> Content-1</divr>
<div class="drop_list"> List-1</div>
</div>
<div class="drop_head">
<div class="dropper"> Content-2</divr>
<div class="drop_list"> List-2</div>
</div>
when content-1 is clicked list-1 has to toggle and when content-2 is clicked list-2 has to drop down... how do i achieve this using single jquery..?? thanks in advance......
If i understand you correctly this should be pretty simple:
$('.drop_head').each(function(i,e){
$('.dropper', e).click(function(){
$('.drop_list', e).slideToggle();
});
});
by using the .drop_head as the context for the list and clickable element you dont need to use id's. additionally if you omit a list or dropper by accident it will only screw up that one "widget" and wont effect the others, which wouldnt be the case with closest.
you have two way (that I see =))
-just give two different ID names to your couples drop-list/dopper
<div class="dropper" id="id_1"> Content-1</divr>
<div class="drop_list" id="id_1"> List-1</div>
<div class="dropper" id="id_2"> Content-2</divr>
<div class="drop_list" id="id_2"> List-2</div>
and then say something like:
$(".dropper #id_1").click(function(){$("#id_1").slideToggle("slow")})
or shorter:
$(".dropper").click(function(){$(this).closest('drop_list').slideToggle()})
Hope it helps
Luca

MVC Multiple submit buttons on a array of objects

I've got a list of objects in an MVC view, each with a set of submit buttons - Move up, Move down and Remove.
Using the answer from this question, I can get the button clicked - but I need to know which item it would be operating on.
The problem comes from the fact the input's value attribute is passed back, I need more information than that - i.e. an id.
Below is a snippet of the contents of a for loop, rendering each item.
<ul>
<li><input type="submit" name="SubmitButton" value="Move-Up" class="linked-content-position-modifier" /></li>
<li><input type="submit" name="SubmitButton" value="Move-Down" class="linked-content-position-modifier" /></li>
<li><input type="submit" name="SubmitButton" value="Remove" class="linked-content-modifier" /></li>
<li><%= Model.Contents[i] %></li>
</ul>
When the form is posted back, I can see that the SubmitButton has a value of either Move-Up, Move-Down or Remove - but no idea which item in the array it's referring too.
Without changing the value to something really ugly, how would I tell which item it's referring to?
Just a quick idea, but maybe you could try adding hiddenfield to each row and see which one gets submitted?
Why are you using a button?
Could a link work instead?
Move Up
I use similar code to update items in a table, but I do it with javascript and update the table accordingly...
<script type="text/javascript">
$('img.action').click(function(){
var itemId = this.attr('id'); // Do some parsing of the id here, i use a format of bi-##
$.ajax({ uri: 'controller/MoveUp/' + itemId });
});
</script>

jQuery inconsistent .remove by class on element with multiple classes

I've got a page where messages and associated elements (responses, forwards, etc) all share a class based on the database id of the parent.
For example
<pre>
<div id="recentMessages">
<div id="a3" class="message a3">this is a message</div>
<div id="a5" class="message a5">this is another message</div>
</div>
<div id="recentComments">
<div id="a3" class="comment a3">this is a comment</div>
<div id="a5" class="comment a5">this is another comment</div>
</div>
<div id="recentActions">
<div id="a3" class="action a3">tim posted a new message</div>
<div id="a4" class="action a4">sara forwarded a message to john</div>
</div>
</pre>
at times I need to remove all elements with the same id, so I originally had
jQuery('div#'+id).remove();
but that would sometimes not remove all the ids because ids are supposed to be unique.
So I added the id as a class. now I use
jQuery('div.'+id).remove();
but this seems to be about 80% effective, and sometimes the divs aren't being removed.
I'm not sure if the issue is because the div has more than one class, but I need the classes because that is how I refer to the elements when somebody clicks.
For instance,
jQuery('div.message').click(function(){
get the id, send it to the server and get the message
});
is there something wrong I'm doing here? or is there a better way to do this?
Looks like this was an issue where a function was being called using a variable which had already been defined. I didn't realize this would cause a problem.
For instance:
jQuery('div','div#recentActions').click(function(){
var removeId=jQuery(this).attr('id').replace('','a');
removeDiv(removeId);
});
function removeDiv(removeId){
jQuery('div#a'+removeId).remove();
}
I can't say for sure this was the issue, but changing the function to:
function removeDiv(cancelId){
jQuery('div#a'+canceld).remove();
}
seems to be working.

Selecting child div by id knowing a parent div id with JQuery selectors

I have this html:
<div id="top">
<div id="potato"></div>
</div>
<div id="bottom">
<div id="potato"></div>
</div>
I am trying to use JQuery to access the bottom potato div, and none of the following work.
$('#top #potato').html('Russet');
$('#bottom #potato').html('Red');
$('#top > #potato').html('Russet');
$('#bottom > #potato').html('Red');
$('#potato').html('Idaho');
All of these just modify the top div and not the bottom one. How do I modify the bottom div?
All elements must have unique IDs, in this case you may use the class attribute, so that you have
<div class="potato" />
Which you may access like this:
$('#bottom > .potato').html('Idaho');
I just ran into this problem. Although it's true you shouldn't have two items with the same ID, it happens.
To get the div you want, this is what works for me:
$('#bottom').find('#potato');
For one thing you can not have an element that has the same id as another. Id is unique, but class names can be used as many times as you want
<div id="top">
<div id="potato1"></div>
</div>
<div id="bottom">
<div id="potato2"></div>
</div>
jquery as so:
$(function{
$("#potato2").html('Idaho'); //if you're going to name it with an id,
// that's all the selector you need
});
What you posted and said doesn't work seems to work to me.
$('#top #potato').addClass('Russet');
$('#bottom #potato').addClass('Red');
https://jsfiddle.net/wzezr706/
no need to put classes on everything, but you should have unique id's for everything. That aside, try this:
$("#bottom + div").html('Idaho');
Try this:
$("#bottom #potato").html('Idaho');
Or
$("#bottom #potato:last").html('Idaho');
your HTML is not valid, since you have non-unique ids