Textarea handling with meteor - meteor

I'm back with a really stupid question this time.
I have a text area in my html, and want to get its value on a Meteor event.
Like for many of my element, i do :
var foo = tmpl.find('#myID').value;
But for my text area, nothing I tried worked.
I tried :
var foo = tmpl.find('#myID').value;
var foo = tmpl.find('#myID').val();
var foo = tmpl.find('#myID').text;
var foo = tmpl.find('#myID').html;
var foo = tmpl.find('#myID').innerHTML;
Without a single result other than a recusive with innerHTML.
Wtf am i doing wrong? I used to do one of the two first when i was working on ancient project, without meteor.
Thanks you.

You can just use jQuery like this: $('#myID').val(). Using find here doesn't really make sense since ids must be unique.

Related

Meteor - Reactive Objects/Classes

TLDR
I like to really focus on keeping business logic away from the view model / controller. I find this sometimes rather hard in Meteor. Maybe I'm missing the point but I am after one of two things really:
1) A really good document explaining at a really low level how reactive values are being used.
2) A package that somehow manages an object so that if any of the setters are altered, they notify all of the get functions that would change as a result.
Unfortunately I've not seen either.
My Example
I have a fair bit ob business logic sitting behind a dialog used to document a consultation. I might have an event that sets a change of state.
I'd like to do something like this in the event:
const cc = new ConsultationEditor();
cc.setChiefComplaint(event.target.value);
console.log(cc.data());
ConsultationDict.set("consEdit", cc.data() );
When the user has updated this value, I'd then like to show a number of fields, based on the change. For this I have a helper with the following:
fields: function(){
console.log("trying to get fields");
const obj = ConsultationDict.get('consEdit');
cc = new ConsultationEditor(obj);
return cc.getFields();
}
But unfortunately this does not work for me.
What is your ConsultationDict?
The way you describe it, you want it to be a ReactiveDict as in the official ReactiveDict package.
https://atmospherejs.com/meteor/reactive-dict
Check this tutorial for examples:
https://themeteorchef.com/snippets/reactive-dict-reactive-vars-and-session-variables/
If you really need more fine tuning in your reactivity, you can also set a dependency tracker tracker = new Tracker.Dependency, and then refer to it wherever you change a variable with tracker.changed() and where the data needs to be notified with tracker.depend() like this:
var favoriteFood = "apples";
var favoriteFoodDep = new Tracker.Dependency;
var getFavoriteFood = function () {
favoriteFoodDep.depend();
return favoriteFood;
};
var setFavoriteFood = function (newValue) {
favoriteFood = newValue;
favoriteFoodDep.changed();
};
getFavoriteFood();
See the full Tracker doc here:
https://github.com/meteor/meteor/wiki/Tracker-Manual
I also found this gist to be useful to build reactive objects:
https://gist.github.com/richsilv/7d66269aab3552449a4c
and for a ViewModel type of behavior, check out
https://viewmodel.meteor.com/
I hope this helps.

Caliburn.Micro multiple element custom Conventions (NumericUpDown.Value,NumericUpDown.Maximum)

I've been messing around with CM conventions trying to understand how they work but i haven't found a decent article somewhere explaining step-by-step how and why.
However I've found a few code snippets that i've been working with with some success.
In this case, however, i don't understand what is going on.
I'm trying to bind a NumericUpDown Value and Maximum to a corresponding ViewModel property. I was able to do it with the following code:
Value
ConventionManager.AddElementConvention<NumericUpDown>(NumericUpDown.ValueProperty, "Value", "ValueChanged");
Maximum
ConventionManager.AddElementConvention<NumericUpDown>(NumericUpDown.MaximumProperty, "Maximum", "MaximumChanged");
var baseBindProperties = ViewModelBinder.BindProperties;
ViewModelBinder.BindProperties =
(frameWorkElements, viewModels) =>
{
foreach (var frameworkElement in frameWorkElements)
{
var propertyName = frameworkElement.Name + "Max";
var property = viewModels.GetPropertyCaseInsensitive(propertyName);
if (property != null)
{
var convention = ConventionManager.GetElementConvention(typeof(NumericUpDown));
ConventionManager.SetBindingWithoutBindingOverwrite(
viewModels,
propertyName,
property,
frameworkElement,
convention,
convention.GetBindableProperty(frameworkElement));
}
}
return baseBindProperties(frameWorkElements, viewModels);
};
However, an here comes the weird part, i can only make one of them to work. That makes me believe that i'm doing some noob mistake somewhere. It almost seems i can only call AddElementConvention and therefor only the last call is executed.
I would appreciate either a help with this piece of code or a reference to some good documentation that could help me with it.
Best Regards
i found out somewhere that CM only allows one convention per item so that's the reason of this behavior...
However since items like ComboBox allows binding for multiple properties (SelectedItem, ItemSource and so on...) i'm not completed convinced...

SDL Tridion GetListKeywords using Anquilla Framework

I'm writing a GUI extension and using the Anquilla framework to get a list of Keywords within a Category. I'm obtaining an XML document for the list of keywords then working with that document within my extension.
My problem is that the returned XML doesn't contain the Keyword's 'Description' value. I have the Title and Key etc.
My original code looks like this:
var category = $models.getItem("CATEGORYTCMID:);
var list = category.getListKeywords();
list.getXml();
A typical node returned is this:
<tcm:Item ID="tcm:4-1749-1024"
Type="1024" Title="rate_one" Lock="0" IsRoot="true"
Modified="2012-12-17T23:01:59" FromPub="010 Schema"
Key="rate_one_value" IsAbstract="false"
CategoryTitle="TagSelector"
CategoryID="tcm:4-469-512" Icon="T1024L0P0"
Allow="268560384" Deny="96" IsNew="false"
Managed="1024"/></tcm:ListKeywords>
So I've tried using a Filter to give me additional column information:
var filter = new Tridion.ContentManager.ListFilter();
filter.columns = Tridion.Constants.ColumnFilter.EXTENDED;
var list = category.getListKeywords(filter);
Unfortunately this only gives the additional XML attributes:
IsShared="true" IsLocalized="false"
I'd really like the description value to be part of this XML without having to create a Keyword object from the XML. Is such a thing possible?
cough any ideas? cough
I'm afraid you'll have to load the Keyword itself to get the Description.
It's not used in any lists, so it's not returned in the XML.
You could always create a List Extender to add this information to the list, but try to be smart about it since this extender will execute everytime a GetList is called.
Won't save you from having to open every keyword in the list, but you'll be doing it server-side (with Core Service/NetTcp for instance) which will probably be easier and faster than opening each keyword with Anguilla.
In this instance I only need the one keyword, so I simply get it from the CMS. Getting an object in Anguilla is a bit weird, here's the code:
In your main code area:
var selectedKy = $models.getItem("TcmUriOfKeywordHere");
if (selectedKy.isLoaded()) {
p.selectedKy = selectedKy;
this.onselectedKyLoaded();
} else {
$evt.addEventHandler(selectedKy, "load", this.onselectedKyLoaded);
selectedKy.load();
}
It's worth noting how I store the keyword in the properties of the item, so I can obtain it in the onselectedKyLoaded function
The function called once the item is loaded
ContentBloom.ExampleGuiExtension.prototype.onselectedKyLoaded = function (event) {
var p = this.properties;
var selectedDescription = p.selectedKy.getDescription();
// do what you need to do with the description :)
};
I resolved this, thanks to the answer here: https://stackoverflow.com/a/12805939/1221032 - Cheers Nuno :)

jQuery add elements to empty selection?

Why doesn't this work?
var spans = $();
var elem = document.getElementById('someId');
spans.add(elem);
What is the proper way to start off with an empty collection and add elements to it?
I want to loop through a collection of ids and find the element on the page and add it to the matched set.
Quoting from the jQuery website:
Given a jQuery object that represents a set of DOM elements, the .add() method constructs a new jQuery object from the union of those elements and the ones passed into the method.
Hence, when you do .add() it will not save the added elements, you would have to explicitly assign the element to the newly created object i.e
var $elements = $('.elements');
$elements = $elements.add($('#anotherelement'));
The .add() method returns a new jQuery object, so you'd need to overwrite the old one:
spans = spans.add( elem );
...or since you're adding DOM elements, you can modify the existing jQuery object with .push().
spans.push( elem );
EDIT: Changed .pushStack() to .push(), though I don't know if .push() is officially supported.
You could use .pushStack() to add a collection though.
spans = spans.pushStack( [elem] );
or
spans = spans.pushStack( document.getElementsByTagName('div') );
I guess I don't get what you're asking. If you have an element and you want to add it to a collection, you just use the .add() method just like you've already shown. What confuses some is that this returns a new jQuery object so you would do it like this:
var spans = $();
var elem = document.getElementById('someId');
spans = spans.add(elem);
Of course, something like this would be shorter:
var spans = $();
spans = spans.add('#someId');
And, of course, you don't have to start with an empty object. You would just start with:
var spans = $('#someId');
If you're looking to push or add items selected from a jQuery object, you could also do this:
var $els = $(),
$someEls = $(".some-els");
$els.push.apply($els, $someEls);
Just another way to do it.
What you actually want to do is use jQuery to it's full potential. You can use selectors to grab and create the collection right away. Your three lines above becomes one line:
var spans = $('#someId');
to add more ids to the collection, you can separate them with commas:
var spans = $('#someId1, #someid2, #someid3');
There may be better ways to do what you're trying, but if you just want to create an empty jQuery object, use this:
var $foo = $([]);
Edit: I should clarify - your code actually should work, unless you're using an older version of jQuery, in which case $() would create a collection containing the document object. In newer versions, however, there's nothing wrong with that. The code snippet I pasted above is just something that should work in older versions and newer versions of jQuery.
Edit 2: In response to this portion of the question: "I want to loop through a collection of ids and find the element on the page and add it to the matched set", the following code might be useful:
var ids = ['foo', 'bar', 'baz'],
selector = $.map(ids, function(i, id) {
return '#' + id;
}).join(','),
$collection = $(selector);
While this doesn't directly answer the question of "how to append to an existing jQuery selection", I have a work-around for this particular use-case.
You can pass an array of DOM elements to jQuery, and it will create a jQuery selection out of them.
var spansArray = [];
var elem = document.getElementById('someId');
spansArray.push(elem);
var spans = $(spansArray);
I can't think of any reason why you would need to add each element to the jQuery selection one-at-a-time, as opposed to all-at-once, so this should be a "drop-in-replacement" for your use case. In theory, this must also prove more efficient, as jQuery's .add() is ultimately just calling .push() on some array behind the scenes.
Try
var spans = $("<span />");
var elem = $("#someId").html();
spans.append(elem).appendTo('#someAnotherId');
instead
The reason your code doesn't work is because add does not change the collection, it returns a new jQuery object with the new elements in it. If you wanted, you could instead say spans = spans.add(elem);, but what you're doing is unnecessary: the beauty of jQuery is that it makes this sort of imperative programming unnecessary. Look at helloandre's answer for a much easier way to accomplish your goal.
It's like the following, if this makes sense:
var x = [1, 2, 3];
x.concat(4);
console.log(x); // [1, 2, 3] -- concat does not mutate the original array

.toggle(true) throw null in $(document).ready(function())

I am toggling row siblings. I wrote .toggle(true) when document ready. see below picture. I think row sibling are not availble before this function calls.
$(document).ready(function() {
$('tr[#class^=RegText]').hide().children('td');
list_Visible_Ids = [];
var idsString, idsArray;
idsString = $('#myVisibleRows').val();
idsArray = idsString.split(',');
$.each(idsArray, function() {
if (this != "") {
$(this).siblings('.RegText').toggle(true);
list_Visible_Ids[this] = 1;
}
});
How to resolve this? why sliblings are not avaible in when document is ready?
Your posted code doesn't match the debugger code, your code has this, which is (almost!) correct:
$(this).siblings('.RegText').toggle(true);
The debugger has this, which is incorrect:
$(this).siblings(('.RegText').toggle(true));
You need to update whatever you're actually debugging to that code without the extra parenthesis, otherwise you're going to get some pretty funky behavior there.
Also you need a # in there since your debugger shows you're not storing the hash mark in the array, which is perfectly fine. You're currently calling $("row10") (which looks for <row10> elements), but what you need is $("#row10") (which looks for id="row10" elements), so adjust your call like this:
$('#' + this).siblings('.RegText').toggle(true);

Resources