jQuery not using selected element - javascript

I am building a custom WordPress plugin that requires me to build into it a custom media library button that lets a user associate an image with a certain option for a post. The user needs to be able to add the elements dynamically, so there are multiple options, i.e. multiple medial library buttons.
The issue that I am running into is that if I have 5 options with five buttons, setting the first image works fine. But if I click buttons 2-5 to set the images for the additional options, they are not getting set but the first option is changing.
It's almost like once the initial element is set on click, then it never changes.
Here is a sample of the HTML (the generic.jpg is the default image before the image is set from the library):
<div class="image-preview-wrapper">
<img class="image-preview" src="https://WEBSITE/wp-content/plugins/atas_spec_writer/admin/assets/generic.jpg" style="max-height: 100px; width: 100px;" width="100" height="100">
<input type="button" class="button upload_image_button" value="Add Image">
<input type="hidden" name="options[section_4][3][img_id]" class="image_attachment_id" value="">
</div>
Here is the JS code:
// Uploading files
var j = jQuery;
var file_frame;
j(document).on('click', '.upload_image_button', function(event) {
var el = j(this);
event.preventDefault();
// If the media frame already exists, reopen it.
if (file_frame) {
// Open frame
file_frame.open();
return;
}
// Create the media frame.
file_frame = wp.media.frames.file_frame = wp.media({
title: 'Select a image to upload',
button: {
text: 'Use this image',
},
multiple: false // Set to true to allow multiple files to be selected
});
// When an image is selected, run a callback.
file_frame.on('select', function() {
// We set multiple to false so only get one image from the uploader
attachment = file_frame.state().get('selection').first().toJSON();
el.siblings('.image-preview').attr('src', attachment.url);
el.siblings('.image_attachment_id').val(attachment.id);
});
// Finally, open the modal
file_frame.open();
// Restore the main ID when the add media button is pressed
j('a.add_media').on('click', function() {
wp.media.model.settings.post.id = wp_media_post_id;
});
I've switched up using j(this), event.target, and they both seem to stick with the first element clicked.
I originally thought that it might just go to the first element in the DOM that matches what is clicked, but if I add 2 options with images and then come back two days later and add two more, the click event sticks with the first element that was set that day, not the first element in the DOM.
So I am completely at a loss......
Any help is much appreciated!!

Looks like once you open a frame file_frame variable will never be nullified or resetted.
I guess problem lies in the following return statement:
if (file_frame) {
// Open frame
file_frame.open();
return;
}

Related

how to close one panel when opening another using Polymer

I have an iron-list in which I have a settings icon which, when clicked causes a panel to slide out with settings options in. However when I have one open, I am wanting it to close upon opening the panel for another row. Currently I have it where they can all be open at the same time which is not optimal.
Please see the gif for the problem I am facing.
GIF OF THE PROBLEM
HTML/Polymer
<div class="container horizontal layout">
<div class="settingsIconContainer">
<paper-icon-button class="settingIcon" icon="settings" on-click="toggleSettings"></paper-icon-button>
</div>
<div id="edit" class="settings">
<paper-icon-button icon="delete"></paper-icon-button>
<paper-icon-button icon="create"></paper-icon-button>
<paper-icon-button icon="clear" on-click="toggleSettings"></paper-icon-button>
</div>
</div>
Polymer JS
toggleSettings : function(e) {
this.$.edit.classList.toggle('settingsMove');
},
You should not access the parent element from the child element. There are two ways of doing this.
1) In the toggle class, fire an event as below
toggleSettings : function(e) {
this.fire('settings-icon-toggle');
}
In the parent element add a listener and listen to the fired event.
listeners:{
'settings-icon-toggle': '_onSettingsIconToggle'
},
_onSettingsIconToggle: function(e){
//Using e.target.id, loop through all the settings and close them except the current one.
}
2) Add a boolean property in the object that you're passing to the iron-list, pass it to the settins component and set the property to true in the tolggleSetings method.
toggleSettings : function(e) {
this._isOpen = false;
}
In the Parent component, add an observer to this property and set all the rest of them to false.
observers:['_listChanged(arrayToIronList.*)'],
_listChanged:function(){
var isOpenSubPath = e.path.indexOf('._isOpen')
if( isOpenSubPath >=0){
var index = parseInt(e.path.match(/\d+/g)[0]);
//loop through the array and set all the _isOpen properties to false except the current one.
//You can find the current one using the index.
}
}
Did i misunderstood your question or is this question that simple?
You are trying to have only 1 opened settings at a time, right? so when user presses one settings, all others needs to be closed.
Just find all elements with settingsMove class and then remove that class.
toggleSettings : function(e) {
var elems = Polymer.dom(this.root).querySelectorAll(".settingsMove");
for(var i = 0; i < elems.length; i++){
this.toggleClass("settingsMove", false, elems[i]);
}
this.toggleClass("settingsMove", true, e.target.parentNode.parentNode.querySelector(".settings"))
}
i don't know what element you need to set class settingsMove on. So edit e.target.parentNode.parentNode.querySelector(".settings")) to suit your code
I used Polymer native function toggleClass. More info you can find here https://www.polymer-project.org/1.0/docs/api/Polymer.Base#method-toggleClass

Add more links to the Dropdown Menu of meteor-accounts-ui-bootstrap-3

After a user logs in to a site using meteor-accounts-ui-bootstrap-3 package, the dropdown created by {{loginButtons}} shows 2 buttons.
How can we add more buttons to the dropdown menu?
You'll need to customize the package. It should be inside your project's packages/ directory. The file that controls this dropdown is login_buttons_dropdown.html.
Note that running mrt update might affect your changes to meteorite packages. You might want to rename the package folder to something like accounts-ui-bootstrap-3-custom/, do an mrt remove accounts-ui-bootstrap-3, and then mrt add accounts-ui-bootstrap-3-custom.
It is certainly possible to make additions without editing the package files, like injecting code at runtime. Assuming you use iron:router, you can inject HTML code in the client every time before a page renders:
var addExtraHTML = function() {
var user = Meteor.user();
//check if user is signed in and that desired HTML element does not already exists
if (user && $('#idOfDesiredHTMLElement').length===0) {
var newHTML = "<a href='#' class='btn btn-default btn-block' id='idOfDesiredHTMLElement'>Edit Account</a>";
//Add desired HTML above the change password button
$('#login-buttons-open-change-password').before(newHTML);
}
this.next();
};
Router.onBeforeAction(addExtraHTML); //Injects HTML every time before the page loads
Make sure to give the things you add an id, so that you can keep track of what is already there!
Meteor has changed since the last answer was valid.
The way I got it to work was by attaching to the onRender event of the dropdown template from the accounts-ui package.
Tested on:
METEOR#1.1.0.3 - accounts-ui-unstyled#1.1.7
Template._loginButtonsLoggedInDropdownActions.onRendered(function() {
// Validate user exists and YOUR ELEMENT is not already in place
if (Meteor.user() && $('#YOUR_ELEMENT').length === 0) {
// Inject YOUR ELEMENT before the 'Change password' button
$('#login-buttons-open-change-password').before('<div class="login-button" id="YOUR_ELEMENT">YOUR_ELEMENT</div>');
// EXTRA: Attach an event to YOUR ELEMENT
$('#login-buttons-open-account-page').on('click', function() {
// Event Action...
});
}
});

passing form values from fancy box popup to main window

I am currently working on a web app using python and Django, and i have a screen with a popup using the fancybox jquery plugin.
When the link is clicked it opens a url on my server which is basically a form.
What i am trying to achieve is the ability to pass the values of the form inputs to my main page once the popup is closed.
I have a funny feeling that is isnt going to be possible and i might be better off using hidden divs (which hide so on command) rather than a popup.
my test page:
<div class='link'>
<a class='fancy' href='create/' > click me </a>
</div
the javascript atm:
$(function(){
$('.fancy').fancybox(
{
type:'ajax',
afterClose: function(){
alert('done!');
}
}
});
The main idea is the popup has a form which has values which will be added to the Django database, but there is also a table on the main window which also displays these.
I wanted to make the main window to be the one which creates the object, saves it and then loads it into the form ( this is taken care of from a API call which i use ajax)
any help at all would be great
Following is a very simplistic pub/sub that creates a stored object and updates object and page elements using change event of form inputs
Html:
<!-- table, match "data-bind" to form input name -->
<td data-bind="fname" class="subscriber">Foo</td>
<td data-bind="lname" class="subscriber">Bar</td>
<!-- form -->
<input type="text" name="fname" class="data_source" />
JS:
/* declare empty object */
var storedData = {};
var $subscribers=$('.subscriber');
/* this event triggered when input changes*/
$(document).on('upDataData', function( event, key, value){
storedData[key]=value;
$subscribers.filter( '[data-bind="'+key+'"]').text( value );
});
/* change handler for form inputs*/
$(document).on('change', 'form input.data_source', inputChange);
function inputChange(){
$(document).trigger('upDataData',[ this.name, this.value]);
}
/* populate storedData from table elements when page loads*/
function createInitialData(){
$subscribers.each(function(){
storedData[ $(this).data('bind')]= $(this).text();
});
}
createInitialData()
Then in your fancybox code send object to server and parse values into form with server code:
$('.fancy').fancybox({
type:'ajax',
/* same as "options" for "$.ajax"*/
ajax: { data : storedData},
afterClose: function(){
alert('done!');
}
});
DEMO: http://jsfiddle.net/xg9ML/2/

Single paged website, which i want to get at a certain point after refreshing page

I have a single paged website, in which i've got a div named sitecontent with the width of 4400, which holds 4 "pages". The pages start at 0px of sitecontent, 1100 px of sitecontent, 2200px of sitecontent, and 3300px.
I use Jquery to set de div position to the right px, so i get the right text displayed. After pressing a link i get for example:
<div id="site-content" style="left: -1100px;">
At one of the pages i have to refresh the page, and after this refresh i want the page to display the same "page" on 1100px, but it starts at 0px, the home page.
Is there any way how i can make sure that the sitecontent starts at -1100px of home?
Thanks in advance,
Cheers
You need to append some identifier onto the hash of the URL that you can parse on the page load.
For example:
http://www.somewebpage.com/somepage#page1
Then in the load of the page, you can inspect this hash value and immediately change the UI to show the new page:
var hash = window.location.hash;
if(hash == "#page1")
$('#site-content').css('left', '-1100px');
You can use a cookie to store the value, then, every time the page loads, you need to check the cookie and deal with the value collected:
The link for Jquery Cookie with download and usage manual!
HTML (example)
<a href="#" title="Go Page 1" id="page_01" class="setCookie">
Click to view page 01
</a>
JQUERY (jquery.cookie)
// SET THE COOKIE
$('.setCookie').bind("click", function() {
var pageNumber = $(this).attr("id");
$.cookie('the_cookie_name', pageNumber, { expires: 7, path: '/' });
});
// READ THE COOKIE
$(function() {
var oldNumber = $.cookie('the_cookie_name');
if (oldNumber !== NULL) {
$("#page_"+oldNumber).trigger("click");
}
});
Note:
The link that you currently use to change pages, should have the class "setCookie" to trigger the cookie creation, and also the id that is being used to identify the page number.
One advantage of this is that you can control for how long is the cookie preserved and thus allowing the visitant to resume the website experience.
An approach very similar to what Tejs is proposing would be to use a hash-based routing framework that listens to hash changes. That will result in much cleaner code since you don't need to define the scrolling in two different places.
Every link in your page is currently being observed by a jQuery event listener (onclick -> moves the content container to the show the desired content). The HTML looks probably somewhat like this: Contact details.
With this approach, you don't need to watch those links. Instead, simply make them change the hash: Contact details.
Now observe the hash and react to changes. I'm using the Simrou framework (https://github.com/buero-fuer-ideen/Simrou) but you can go with any other framework that provides similar functionality.
jQuery(document).ready(function() {
// Define a function that moves the content, e.g. moveContent(3300);
function moveContent(pixelPosition) {
$('#site-content').css('left', '-' + pixelPosition + 'px');
}
// Setup the router
var router = new Simrou({
'page1': function() { moveContent(0); },
'page2': function() { moveContent(1100); },
'page3': function() { moveContent(2200); },
'page4': function() { moveContent(3300); }
});
router.start();
});
That's all the javascript you need!
(and here is a quick and dirty fiddle, demonstrating the whole thing: http://jsfiddle.net/R7F6r/)

Display a chart in a pop-up/modal on mouse click (jquery?) without loading chart first? (mvc3/razor)

I'm using the FileStreamResult (or FileResult) method to display a chart on a razor view page (from a Controller action) and this works as expected.
However, I'm wondering if it's possible to display the chart ONLY when an html element is clicked.
e.g. Click on an element, display chart in modal pop-up.
I can get a modal to display using Jquery...but ONLY if I have already loaded the chart into a div.
I'd like to have the page load without the chart (for performance reasons), and then only generate/load the chart when the is clicked.
I guess I need an Ajax call of somekind...but I'm a little stuck as to how to proceed and googling didn't return anything useful (just lightbox for photos)
Pseudo Code:
HTML:
<img src='small chart icon.jpg' alt='click me to see chart' id='showchart'/>
<div>
rest of page goes here...
</div>
C#:
public FileStreamResult GetChart(){
//generate any chart
return FileStreamResult(newchartstream, "image/png");
}
JS:
<script>
$(document).ready(function(){
$('#showchart').click(function(){
//make ajax call to generate chart
//show in modal with "close" button
//OR
//open a new page as a modal?
});
});
</script>
EDIT
Clarification:
Controller generates a ViewModel (from an EF4 model) which contains the results of lots of calculations, and some "summary" rows (totals, averages etc)
View displays the results (ViewModel) as tables.
Requirement:
Click on one of the summary rows, opens modal window displaying a chart for that summary row.
Would like to avoid sendind the parameters for the ViewModel and re-generating it from scratch (doing all the calcs again etc) for two reasons
1) The figures in the back-end db may have changed...so the chart doesn't reflect whats being shown in the tables.
2) It takes time to do the calcs!
I'd also like to ONLY generate the chart if the row is clicked, as opposed to loading the chart always and hide() show() with jquery.
I've thought about an ajax call, but unsure about how to return an image, or how to open a new page.
Can't see a way to pass a complex model in the Url.Action() method.
Think caching may be the best option, and have the click method call "old fashioned" javascript for a new window, passing over the parameters to get the object from cache?
You have many ways to do that, but here is what I would do.
1/ Create an action which returns a tag with the good src (assuming that your controller's name is ChartsController).
public ActionResult GetImage(int chartId = 0)
{
var image = #"<img id='chart' src='" + Url.Action("GetChart", new {controller = "Charts", chartId = chartId}) + #"'/>";
return this.Content(image);
}
2/ I assume that, in your view, you have a div somewhere which contains your modal's content (like jQuery-ui would do) with an img inside, for the chart.
<div id="modal-div">
<div id="chart-div"></div>
</div>
3/ For every row, you have to create an Ajax link who will call your "GetImage" action and replace "chart-div" with your . You can specify a "OnBegin" Javascript function, this is where you will put your code to launch the modal.
#Ajax.ActionLink("Show me the chart!", "GetImage", "User", new { chartId = #Model.Rows[i]}, new AjaxOptions()
{
HttpMethod="GET",
OnBegin = "showModalWindow",
UpdateTargetId="modal-div",
InsertionMode = InsertionMode.Replace
});
Everytime you will click on an Ajax link, the modal will be launched and the inside will be replaced (in fact, all the content of the modal will be replaced).
Don't forget to include "Scripts/jquery.unobtrusive-ajax.js" and "Scripts/jquery.validate.unobtrusive.js" for the Ajax links to work.
You have some difference question mixed in one. You should split them each in one question. For your question's title, -loading an image by AJAX- you can use code-snippet below:
HTML:
<div id="chartholder"></div>
<a id="showchart">Show the chart</a> <!-- or any element else you want to fire show event -->
JS:
$(document).ready(function(){
$("#showchart").click(function(){
// Put your controller and action (and id if presented) below:
var file = "/YourControllerToGetChart/GetChart/id"
$("<img />").attr("src", file).load(function () {
$(this) // the loaded image
.css({"some-css-you-want":"some-value"})
.appendTo($("#chartholder")); // fixed syntax
});
});
});
Let me know if you have any questions or need clarifications on any part or you want to know how to css the div id="chartholder" to display it as an modal. Cheers.

Categories

Resources