I have two observables, one that specifies a module name and the other that sets a height for some of its children. I am trying to make a custom css computed observable that includes these two observables like so:
self.moduleId = ko.observable('dbm-name');
self.slideWidth = ko.observable(75);
self.css = ko.observable('');
self.setcss = ko.computed({
read: function() {
return '#' + self.moduleId() +
' {\n\tbackground: #fff;\n\tcolor: #000;\n}
\n.cont_width {\n\twidth: ' + self.slideWidth() +
'%;\n}';
},
write: function(value) {
self.css(value);
return value;
}
});
but it should also allow the user to manually write/edit some css. The problem is that once either moduleId or slideWidth is changed the css observable is not updated unless the user goes into the custom css textarea and makes a change (ie. add and remove a space just to get it to update). How can I automatically update the css observable when either of the other two observable values change? Or is there a better way of setting up my css functionality?
You can specify the read function to also set your css:
self.setcss = ko.computed({
read: function() {
var _css = '#' + self.moduleId() +
'{\n\tbackground: #fff;\n\tcolor: #000;\n}' +
'\n.cont_width {\n\twidth: ' + self.slideWidth() +
'%;\n}';
self.css(_css);
},
write: self.css
});
But like this you can only have one of the values as your css, either the user typed css or the computed product, at each moment in time.
But I suppose you could modify the read in such a way that it either concatenating the values to add the new one at the end of the css you already have.
here is a working fiddle
Related
var = cooldynamicelement
How could I store the inner html I grab with jQuery from my div ie. <div class="username"> </div> to store as an accessible variable in jQuery eg. cooldynamicelement so I can grab and use at different areas of my site by just calling ie. $cooldynamicelement and updates with the dynamic .username element value.
1. Store HTML into localStorage
var dynamicElementHTML = localstorage.dynamicElementHTML || $(".username").html() || "";
localstorage["dynamicElementHTML"] = dynamicElementHTML;
To make it available to other pages a way would be to use the power of localstorage
https://developer.mozilla.org/en/docs/Web/API/Window/localStorage
If you're actually interested in the whole element (not only it's inner HTML) than instead of .html() use .prop("outerHTML")
2. Binding using jQuery (essential idea)
If you only want a way to reflect some variable HTML as actual html and make it alive you could do like:
var $myElement = $("<div />", {
class : "userData",
append : $someDynamicElements,
appendTo : $someParentElement,
on : {
contentUpdate : function() {
$(this).html( $someDynamicElements );
}
}
});
than whenever your $someDynamicElements changes you can trigger a contentUpdate
$myElement.trigger("contentUpdate")
3. Binding using jQuery (concept)
Here's the same elements binding concept gone wild:
// Here we will store our elements
var EL = {};
// Create desired HTML elements like this:
var LIST = {
username: $("<b/>", {
html : "UNKNOWN",
click : function() {
alert( $(this).text() );
}
}),
email: $("<a/>", {
html : "test#test.test",
href : "mailto:"+ "test#test.test"
}),
// add more here, you got the idea.
// don't forget that you can assign any JS / jQuery propery to your element.
// You can go insane using .on() and later .trigger()
};
// Our small "program" that replaces data-bind elements
// with dynamic elements from our list
$("[data-bind]").replaceWith(function(i){
var bind = this.dataset.bind;
if(!LIST[bind]) return;
if(!EL.hasOwnProperty(bind)) EL[bind] = [];
var klon = LIST[bind].clone(true)[0];
EL[bind].push(klon);
return klon;
});
// That's it. Now goes your code ///////////////
$(EL.username).css({color:"red"}); // just to test if it works :D
$("[data-target]").on("input", function(){
var target = this.dataset.target;
$(EL[target]).html( this.value );
});
// P.S: Even having thousands of elements inside EL
// say you have "EL.tableRows" you can do fabulously
// quick stuff like i.e: sorting, cause you iterate over a plain JS array.
// After the sorting of EL.tableRows is done and you need a jQuery
// representation simply use $(EL.tableRows).
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Dynamic element Binding in jQuery</h2>
Enter some text and see the update trigger in different places<br>
<input data-target="username"><br>
Welcome <span data-bind="username"></span> !!<br>
You name is <span data-bind="username"></span> Click the red text!<br>
<span data-bind="email"></span>
Well if you want to have the jqueryObject in a variable, just do this:
$(function(){
window.$cooldynamicelement = $("div.username");
})
that way you're able to use $cooldynamicelement in a global context. If is that what you want. This way you're saving a reference to your .username element and thus every time you use it will be updated.
NOTE: If you decide to do this, be careful with polluting your global context.:
I'm using angularJs and want to change the style of an attribute dynamically.
Normally I would do this with ng-style in the html element.
But I want to apply styles to the track of a range input.
This element can be accessed in css like that: .slider::-webkit-slider-runnable-track(As Example for the webkit selector). Can I change the style for such an attribute in a function where I have the id for this element?
E.g (how I would do it in jquery):
$scope.change = function(id, value) {
$('#'+id+'::-webkit-slider-runnable-track').css('background-image',value);
};
Javascript generally don't have access to pseudo elements, one possible workaround would be to insert a style tag
$scope.change = function(id, value) {
var style = document.createElement('style');
var styles = '{ background: red }';
style.innerHTML = '#' + id + '::-webkit-slider-runnable-track ' + styles;
document.head.appendChild(style)
};
FIDDLE
Another way would be to keep the styles in the stylesheet, and just use a different class for a different style
#test.red::-webkit-slider-runnable-track {
background : red;
}
and then do
document.getElementById('test').classList.add('red');
FIDDLE
for AngularJs I recommend not to use $scope but use service, factory or directory instead for CSS type of work on html template.
however if you must still want to take this approach you can:
$scope.change = function(id, cssClass, add) {
var el = angular.element(document.querySelector(id));
if (add) {
el.addClass(cssClass);
} else {
el.removeClass(cssClass);
}
}
where you can pass id for element, cssClass from your css class and use add as bool value; pass what ever you want.
I have a bunch of divs with matching ids (#idA_1 and #idB_1, #idA_2 and #idB_2, etc). In jquery I wanted to assign click functions, so that when I click an #idA it will show and hide an #idB.
Basically I want to make this:
$(".idA_x").click(function(){
$("idB_x").toggleClass("hide")
});
X would be a variable to make #idA and #idB match. I could write each individually, but that would take too much code, is there a way to make the number in the id into a variable?
Sure, you can do:
var num = 13;
addButtonListener(num);
function addButtonListener(num){
$("#idA_"+num).click(function(){
$("#idB_"+num).toggleClass("hide")
});
}
Try JQuery solution :
var x = 1;
$(".idA_" + x ).click(function(){
$(".idB_" + x ).toggleClass("hide")
});
Hope this helps.
There are many ways to achieve that, but what you probably want is to create a shared CSS class, e.g. .ids, and bind the event listener to that one:
$('.ids').click(function () {
//...
});
Then you can handle your logic in a cleaner way within the function body.
In order to make it dynamic, and not have to repeat the code for each one of your numbers, I suggest doing as follows:
First, add a class to all the div's you want to be clickable .clickable, and then use the id of the clicked event, replacing A with B in order to select the element you what to toggle the class:
$(".clickable").click(function(){
var id = $(this).attr('id');
$("#" + id.replace('A', 'B')).toggleClass("hide");
});
Or, you can also select all divs and use the contains wildcard:
$("div[id*='idA_']").click(function(){
var id = $(this).attr('id');
$("#" + id.replace('A', 'B')).toggleClass("hide");
});
This solution won't have the need to add a class to all clickable divs.
You can use attribute selector begins with to target the id's you want that have corresponding elements.
https://api.jquery.com/attribute-starts-with-selector/
Then get the value after the understore using split on the id and applying Array.pop() to remove the 1st part of the array.
http://jsfiddle.net/up9h0903/
$("[id^='idA_']").click(function () {
var num = this.id.split("_").pop();
$("#idB_" + num).toggleClass("hide")
});
Using regex would be your other option to strip the number from the id.
http://jsfiddle.net/up9h0903/1/
$("[id^='idA_']").click(function () {
var num = this.id.match(/\d+/g);
$("#idB_" + num).toggleClass("hide")
});
How can I locate the tag which calls a JQuery script, when
the tag is dynamically loaded, so won't be the last
tag on the page?
I'm using the MagicSuggest autosuggest library. I want to give certain suggested items a different background color depending on their contents, which I'm currently doing by adding JQuery inside a tag, which I'm adding on to the String which is returned to be rendered inside the selection div. Then, to get the div the item is suggested in, I need to essentially get the parent() of the tag, and change it's css() properties. How can I get this current script tag however?
I'm currently assigned each new tag an id generated from incrementing a JS variable - which works, but isn't very 'nice'! Is there anyway I can directly target the tag with JQuery?
If it perhaps makes it clearer, here is my current selectionRenderer function.
selectionRenderer: function(a){
var toRet = a.english;
var blueBgScript = "<script id=ft" + freeTextFieldID + ">$('#ft" + freeTextFieldID + "').parent().css('background', 'blue');</script>"
if(a.id==a.english){
toRet += blueBgScript;
freeTextFieldID++;
}
return toRet;
},
Why don't you add some code at afterrender event instead? Add some tag to flag the options that need a different background, then detect the parents and add a class (or edit the bg property) or whatever you like:
var newMS = $('#idStr').magicSuggest({
data: 'states.php',
displayField: 'english',
valueField: 'id',
selectionRenderer: function(a){
var toRet = a.english;
if(a.id==a.english) toRet = "<span class='freetext'>" + toRet + "</span>";
return toRet;
},
});
$(newMS).on('selectionchange', function(event,combo,selection){
var selDivs = $(event.target._valueContainer[0].parentNode).children('div'); //Get all the divs in the selction
$.each(selDivs,function(index,value){ //For each selected item
var span = $(value).children('.freetext'); //It if contains a span of class freetext
if(span.length == 1) $(value).css('background','blue'); //Turn the background blue
});
I've got a jQuery UI slider. When the user uses a slider, the slider updates an attr variable in the div tag of the slider
$(".slider").each(function() {
var value = parseInt($(this).attr('data-init-value'), 10);
var amin = parseInt($(this).attr('data-min'), 10);
var amax = parseInt($(this).attr('data-max'), 10);
console.log(value, " ", amin, " ", amax)
$(this).empty().slider({
value : value,
min : amin,
max : amax,
range : "min",
animate : true,
slide : function(event, ui) {
$(this).attr('data-value', ui.value);
}
});
});
The example div tag in the html:
<div class="slider" data-min="200" data-max="600" data-init-value="300" data-bind="attr: { 'data-value': someValue }"></div>
When the slider is changed the data-value is updated in the <div> but the js variable doesn't change. (in other, trivial binding cases - like text: - it works.)
How to bind this action?
I suggest you do this the other way around. Bind the value of the slider to an observable property on your viewmodel, and then bind the attribute to that observable.
Then you can always access the most recent value of the slider directly through the viewmodel, and the UI will stay up to date as well.
And further, if you want to subscribe to the update event of that observable, you can bind to that as well. Here is an example from the documentation:
myViewModel.personName.subscribe(function(newValue) {
alert("The person's new name is " + newValue);
});
And finally, this might as well be a possible duplicate of: Identify the attribute change event in KnockoutJS?
-- Update to answer comments
Given the following viewmodel:
var viewModel = {
mySliderValue: ko.observable(0)
};
Then, in your slider callback, you could do something like this:
viewModel.mySliderValue(value);
And then, in your view, having the following attr binding:
data-bind="attr: { 'data-value': mySliderValue }"
... will cause the UI to update when the observable changes its value.
PS. I suggest you no longer delete this thread since my answer is starting to deviate more and more from the one I linked to.
The way to do it is to register an event handler.
o.utils.registerEventHandler(element, "slidechange", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
JSFiddle for full example:
http://jsfiddle.net/snLk8/3/