I am creating a 'favorites' style system for a property webiste where users can save a property to be viewed later. The system works using Jquery so the page doesn't have to refresh. The details page of a property contains a 'add to favorites button' and this works fine:
$("#addFavorites").click(function() {
var locationID = $("#locationID").val();
But how would I code this when all of the properties are listed together on one page, each 'add to favorites' button would have to use a unique id or something but not sure how to approach this.
Well the most precise way would be a default HTML-Formular. I'll make it a short one:
<form ...>
<label for="fav1">Fav1</label>
<input type="checkbox" name="favorites[]" id="fav1" value="1" />
<label for="fav2">Fav2</label>
<input type="checkbox" name="favorites[]" id="fav2" value="2" />
<submit>
</form>
Now that's the ugly form, you can make this beautiful with CSS. With jQuery you now always submit the form when the user checks any of the checkboxes, like:
$('input[type=checkbox]').change(//do ajax submit);
In the AJAX File you simply read the array:
foreach($_POST['favorites'] as $fav) {
addFavToUser($fav, $user);
}
This is like simply explained to give you an idea, not the whole "clean" solution. But i hope this helps you - if it does, i always appreciate the vote for it ;)
Each of your 'favorites' would need a unique id
...
...
Then..
$('.favorite').click(function(){
$(this).whateveryouwanttodo();
});
$(this) will contain the clicked anchor tag. from that you can get the id, and call your ajax post or whatever you want to do with it.
In jQuery you can use relative positioning to select the item of interest. So, for example, if each item was followed by a favorite button, you can traverse the DOM from the clicked item to find the related item. You can then post this back via AJAX to store it an update the element as needed to reflect the updated status.
HTML (assumes you use styling to show the icon and favorite status)
<span class="normal" data-location="A">Location A</span> <span class="icon-favorite"></span>
JS
$('.favorite').click( function() {
var data = [],
newClass = 'favorite',
oldClass = 'normal',
$this = $(this),
$location = $(this).prev('span');
// if already favorited, reverse the sense of classes
// being applied
if ($location.hasClass('favorite')) {
newClass = 'normal';
oldClass = 'favorite';
}
data['location'] = $location.attr('data-location');
$.post('/toggle_favorite', data, function(result) {
if (result.Success) {
$location.removeClass(oldClass).addClass(newClass);
$this.removeClass('icon-'+newClass).addClass('icon-'+oldClass);
}
else {
alert('could not mark as favorite');
}
},'json');
});
Related
In Google Tag Manager it's quite easy to use the element, element classes, element parent classes to fire tags. Unfortunately in this case I want to scrape an element which is only available in the same .
So, when people click on the link "delete" (class=deleteItem) I want to scrape the url_product_id (in bold).
I've tried so much but can't figure out how to achieve this. I hope somebody can help me out.
<td align="center">
<span class="selquantity menosdis"></span>
<span class="selquantity plus"></span>
<input class="urlProductId" type="hidden" name="url_product_id" value="113293">
<input class="urlQuantity" type="text" name="url_quantity" value="1" readonly="readonly">
<br>
<a style="cursor: pointer" class="deleteItem">delete</a>
</td>
Assuming you are wanting to accomplish this within an event handler, you could use parentNode and querySelector to accomplish your goal:
var myClickHandler = function(event) {
var productId = event.target.parentNode.querySelector('. urlProductId').value;
// do stuff with productId
}
Or with jQuery:
$('.deleteItem').on('click', function() {
var productId = $(this).prev('.urlProductId').val();
});
This is similar to Rob's answer, but also takes into account if code is moved around into additional divs, etc.. Since people update their UI all the time. This should be more sustainable as the product matures. Of course you'll want to watch the .closest() call if you ever change to something like BootStrap data tables.
$(".deleteItem").on("click", function() {
var getClosestProdID = $(event.target).closest('td').find('.urlProductId');
// Just for display of the value
alert("Our closest selected value is: " + getClosestProdID.val());
});
JS Fiddle
Here is a jQuery method (modify and test on your own), and you could do this in a GTM Custom Javascript variable:
function(){
var ce = {{Click Element}}; // get the clicked element
if ($(ce).length > 0){
return $(ce).closest('td').find('.urlProductId').attr('name');
}
return undefined;
}
The premise here being that your elements are all nested under the <td> element, and all you're doing is taking the clicked element and scraping for the element you're interested in.
another question! I am using Ajax to get the updated Billing Domain ID that is associated with the OfficeId Dropdown.
I have the need for an if statement that is changed dynamically. Here is what I am trying to accomplish.
I want for certain fields to be hidden based on the BillingDomainID. For example, if BillingDomainID is 1, I want to hide the fields. The trick is that I want to be able to expand as time goes on so that it can also be used for other IDs as they arise.
Here is what I have so far without any success.
function getOfficeInfo(OID, BDID) {
//alert(OID);
//alert(BDID);
$.post("/UserControls/getOfficeInfo.asp", {OfficeID: OID}, function(data) {
BDID.val(data);
var vBDID
vBDID = ".BillingDomainID" + data;
//alert(vBDID);
if (data != 1) {
$(vBDID).hide();
}
});
//alert(data);
}
I am just needing to know how to make the $(vBDID).hide(); part work.
There are so many ways to go about this, since you have control over the HTML I think you have two direct approaches:
Create a map of fields to Billing Domains Ids
var fieldMap = {
'1': ['first-name', 'last-name', ...],
'2': ['first-name', 'last-name', 'ssn', ...],
...
};
Then you can do something like (assuming data is the billing domain id:
var $form = $('form');
// hide everything by default
$form.find('input').hide();
// show all fields that pertain to this domain
$form.find(fieldMap[data].map(function(field) {
// gives you '[name="first-name"]'), etc.
return '[name="'+field+'"]';
})).show();
Add class names to inputs to indicate which billing domain ids they are shown for
<input type="text" name="first-name" class="domain-1 domain-2 domain-3" />
And then:
$form.find('.domain-'+data).show();
Though I feel like that could get kind of messy if you have a lot of domains.
I'm not sure why your element isn't hiding unless your typing your class name incorrectly. Here's a fiddle that shows how this works.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="someClass" type="button">
Hi there
</button>
$(function(){
var thing = '.someClass';
$('button').on('click', function(){
$(thing).hide();
})
});
I have a DropDownList where onChange sets the content of the TextArea which is my CKEditor control.
When the editor is not in use I run this bit of code for onChange:
$(".setBody").change(function() {
//
var className = "." + $(this).attr("sExternalId");
var text = $(this).val();
//
$(className).val(text);
});
I'm not very experienced with Javascript/JQuery and I just can't figure out how to perform the same using CKEditor's setData() function. This is what I've tried:
$(".setCKBody").change(function() {
//
var className = "." + $(this).attr("sExternalId");
var text = $(this).val();
//
var editor = $(className).ckeditorGet();
editor.setData(text, function() {
alert("The content was set");
});
});
$(".setCKBody").change(function() {
//
var className = "." + $(this).attr("sExternalId");
var text = $(this).val();
//
CKEDITOR.instances[$(className)].setData(text, function() {
alert("The content was set");
});
});
Am I close? I think one of the main limitations is that I have multiple editor controls with the same id and name, only the class can tell them apart which is why I'm using that with the JQuery. I've tried working through some examples online, but I'm not sure how to apply them to this scenario - that's probably my inexperience coming through there...
Thanks.
EDIT
This is how my textarea and dropdownlist appears in view source:
<textarea class="editArea M3" cols="20" id="Body" name="Body" rows="5">
*some text*
</textarea>
<select class="setCKBody" id="Templates" name="Templates" sExternalId="M3">
<option value="some value">Option 1</option>
<option value="some value">Option 2</option>
</select>
The onChange event above is triggered from the dropDownList changing and is linked to the textArea via the "sExternalId" attribute. I realised I used "id" as the attribute name in the example above which was in error, so I changed that.
I use this to set it as a CKEditor control:
<script>CKEDITOR.replaceAll('editArea');</script>
I have between 2 to 6 textarea controls on the same page, created with razor like this:
#Html.TextAreaFor(m => m.Body, new { #class = "span12 editArea " + Model.ExternalId, rows = 5 })
They are contained within a partial view that is used like this:
#foreach (MailTemplateModel oTemplate in Model.Templates)
{
#Html.Partial("_MailPartial", oTemplate)
}
This is why each text area has "Body" set as the id and name. I think this is the heart of the problem, with there being multiple elements with the same id and name CKEditor is not able to select the correct one. I've tried to do CKEDITOR.instances["className"] but that was undefined, whereas doing CKEDITOR.instances.Body did work, but would only ever return the same value.
I'm going to restructure the way the page is created to avoid this, hopefully my issues will be solved at the same time.
Here's a few pointers.
Use class="foo" if you have many things that you refer to as a group, like like here it looks like you would have many setCKBody elements you listen to for change events.
Use id="foo" if you have one single specific thing.
Using the same id and class for one element usually is not the right thing to do.
CKEDITOR.instances[xxx] <-- xxx should be a string, not a jquery object - so CKEDITOR.instances[className] might work better (I can't say not having seen your HTML).
It would help if we saw your HTML; textarea definitions and setCKBody definitions. Do you have many ckeditors and many setCKBody elements?
My original approach to this scenario was all wrong, I had a model that contained multiple mail templates and so I rendered each one via a partial view within the same page so that the user could click to edit any one of them and the details would appear in a modal popup - within the same window. What I wanted to avoid was forcing the user to navigate to another window to edit a mail template, but this lead to multiple elements having the same id and name attributes which prevented me from accessing them correctly.
I've now added a list box where the user can select a template to edit, the selected template is rendered underneath and so avoids the multiple name and id issue. Now I know there is only ever 1 CKEditor control so I can access it in my js like this:
var editor = CKEDITOR.instances.SelectedTemplate_Body;
SelectedTemplate_Body is the name and id of the element I made into a CKEditor control. The onChange function I wrote for the dropdownlist is now written like this:
$(document).ready(function() {
//
$(".setBody").change(function() {
//
var templateId = $(this).val();
//
$.ajax({
type: "GET",
url: msHost + "MailTemplates/UpdateBody",
data: { "templateId": templateId },
cache: false,
dataType: "text",
success: function (data) {
CKEDITOR.instances.SelectedTemplate_Body.setData(data);
}
})
});
});
The tempalteId attribute is the value associated to the dropdownlist selection, this lets me know which template to use for setting the content of my editor control.
MailTemplates/UpdateBody points to a public method in my MailTemplates controller which runs a search on available mail templates and matches against the template Id passed in, the method then returns the body of the template as a string.
public string UpdateBody(string tempalteId)
{
TemplateQuery oQuery;
//
oQuery = new TemplateQuery();
oQuery.Execute();
foreach (MailTemplate oTemplate in oQuery.Results)
if (oTemplate.Id.Equals(templateId))
return oTemplate.Body;
//
return string.Empty;
}
This line replaces the contents of the CKEditor control with the response from the controller method.
CKEDITOR.instances.SelectedTemplate_Body.setData(data);
Thanks #Nenotlep for trying to help out, you gave me a few things to think about there.
I have a page that pulls a list of my clients from a database, I want to add a search box that dynamically, without reloading page, hides all of the clients that do not match the text typed in the box.
Is this possible with javascript, or is there another method I should try?
My list is coded as such pulling the info from a database.
<ul>
<li>Client Name</li>
...
...
...
<li>Client Name</li>
</ul>
JQuery makes it easier for you Here it is in action http://jsfiddle.net/PUNaM/
http://api.jquery.com/contains-selector/
<input id="filter" />
$("#filter").keyup(function(){
$("ul>li").hide();
$("ul>li:contains("+this.value+")").show();
})
I'll assume you're willing to use jQuery.
First, you need to have some way to reference your list and your textbox via javascript. I'll use an id as an example, but it might be anything.
<input type="text" id="search-box" />
<ul id="clients-list">
<!-- clients list here -->
</ul>
Then, on the javascript, you can listen for the keyup event.
$("#search-box").on("keyup", filterClients);
That will make the filterClients function be called when the user releases a key. There are many ways to define that, but I will go the simple way:
function filterClients(event) {
var $search = $(event.target);
var text = $search.val();
var $clients = $("#clients-list li");
$clients.each(function() {
var $client = $(this);
var clientName = $client.text();
var searchMatchesName = clientName.toUpperCase().indexOf(text.toUpperCase()) >= 0;
if(searchMatchesName) {
$client.show();
} else {
$client.hide();
}
});
}
This is not the most efficient or more fancy way to do this, but should be enough to get you started.
Working jsFiddle: http://jsfiddle.net/u5WS3/
Here's some low-hanging fruit for those more comfortable with Javascript than I...
I want to improve a Moodle plugin's admin UI. (Moodle is a PHP-based web app). What I need to do is take what is currently a text box, with semi-colon delimited entries and replace that with a editable list.
The HTML elements I would use is a select list, a text input field and another hidden textfield. I guess a couple of submit buttons too, one for adding, and the other for removing of entries.
The behaviour would be:
Entries can be added to the select list from the visible textbox upon some kind of submit (this cannot reload the page).
The hidden textbox would contain all the entries from the select list, just semi-colon delimited
There's a function to remove entries from the select list that also does not reload the page.
The hidden textbox is updated with add/remove actions
This seems to me like something that's easy enough. Though I'm having a hard time finding a close enough example to rip off.
This sample code is as close as I've found thus far. There's got to be some good examples of precisely this sort of thing out there. Any decent pointers will be rewarded with + votes.
What you want to do is use JavaScript and manipulate with the DOM of the webpage. Basically, the HTML of a webpage is parsed and rendered by the browser into a tree of elements. Each HTML tag like <select> is an element in the tree. You use JavaScript to interact with this tree by performing operations like removing elements from this tree or adding elements to this tree. (Note that preforming operations on the tree will not refresh the page.)
The standardized API to do these sorts of manipulation in JavaScript is known as the DOM. However, many people, myself included, think that this API is very clunky and not nearly expressive enough. Doing even trivial things require tons of lines of code. For this reason, many developers do not use the DOM directly instead using more powerful libraries, such as jQuery, to make their lives easier.
Below is an example of some HTML + JavaScript that I think mimics most of your requirements. Ideally for learning purposes, this would be written purely using the standard W3C DOM API, but since your problem is not that trivial, I resorted to using jQuery instead.
The HTML:
<select id="list" multiple="multiple"></select>
<input id="removeButton" type="button" value="Remove"></input>
<div>
<input id="optionAdder" type="text"></input>
<input id="addButton" type="button" value="Add"></input>
</div>
<br>
<input id="clearButton" type="button" value="Clear All"></input>
<div>Not So Hidden: <input id="hidden" type="text"></input></div>
The JavaScript:
// Uses jQuery to define an on document ready call back function
$(function(){
// The code in this function runs when the page is loaded
var options = []; // contains all the options
// add new option to drop-down
var addOption = function(optText) {
// Create new option element and add it to the <select> tag
$('<option></option>')
.attr('value', optText).text(optText)
.appendTo( $('#list') );
};
// writes the names of all the options in the "hidden" text box
var fillHidden = function() {
$('#hidden').val('');
var hiddenText = "";
for(var i=0; i< options.length; i++) {
if(hiddenText) {
hiddenText += "; ";
}
hiddenText += options[i];
}
$('#hidden').val(hiddenText);
}
// Bind the click event of the "Add" button to add an option on click
$('#addButton')
.click(function(){
var optText = $('#optionAdder').val();
if(optText) {
addOption(optText);
}
$('#optionAdder').val('');
options.push(optText);
fillHidden();
});
// Bind the click event of the "Remove" button to remove the selected options on click
$('#removeButton')
.click(function(){
$('#list option:selected').each(function(){
var optIndex = $.inArray($(this).val(), options);
if(optIndex > -1) {
options.splice(optIndex, 1);
$(this).remove();
}
fillHidden();
});
});
// Bind the click event of the "Clear" button to clear all options on click
$('#clearButton')
.click(function(){
$('#list').children().remove();
options = [];
fillHidden();
});
});
Here is a jsfiddle demonstrating the code