knockoutjs - object's changeTracker/dirtyFlag triggering immediattly - javascript

I recently found and applied the changeTracker/dirtyFlag approach successfully in my code and everything was good. Very neat and useful. Though, today, I was trying to use it again and something weird was happening: the somethingHasChanged trigger was firing as soon as I opened the page.
I looked, searched and nothing. I was not doing any change to the observables after setting the tracker.
After a couple of hours of this, I found the root of the problem:
One of the observables is binded to a <select> element thus setting the currently selected <option>.
If I remove this binding, it no long triggers.
I don't know why this happens, since the value is only read (supposedly).
Any thoughts on this?

My guess would be that you are binding against numeric values and the selected one is being written back to your view model as a string, as KO reads it out of the DOM element.

Related

Select2 dropdown menu persists after select removed from DOM

I am using select2 version 4.0.2(rc1)
What I am seeing is that when using select2 with isMultple=true, opening the dropdown and then dynamically removing the select from the DOM, the menu sticks around.
You can see it happening in the select2 examples by focusing on control so you see the time zone options, then in the console typing $('.s2-example').remove(). The list of options sticks around.
Edit: Above is an example of what I am trying to work around. What is happening in my case is the dom is being manipulated to remove the select box by a framework in such a way that I can't hook into it before it happens. What I am trying to do is find a way to respond to the element being removed in the hopes that I can manually remove the options list if it exists.
I'm trying to figure out a clean approach to handling this. I've tried hooking into destroy like so:
$("#select-2-id").on("destroy", function(){...})
but destroy doesn't appear to be fired.
I have considered using a mutation observer but that feels kind of hacky to me. Could anyone suggest a better way to handle this? Any advice would be appreciated. Thanks!
Definitely buried in the documentation (under adapters), but you should be calling the destroy method on the select by passing "destroy" to the jQuery object's .select2() method
$(".js-example-basic-multiple").select2('destroy');
This destroys the instance. You can then safely call .remove()
$(".js-example-basic-multiple").select2('destroy').remove();

Trigger TypeAhead suggestion selection

For the life of me I cannot figure out how to trigger a suggestion selection on a TypeAhead input
I've tried all kinds of things like
.trigger('suggestionClicked', $('.tt-dropdown-menu .tt-suggestion:nth-child(1)'))
I suppose there are really two parts to this problem.
1. Properly selecting the actual TypeAhead object.
I do this primarily by focusing (focus()) on the input field, and then using jQuery to find the element that is active ($(document.activeElement)). This might not be the best way. It's quite difficult to test in the browser web-inspector because every time I go to the console I lose focus and then the menu disappears (literally removing the results from the DOM)
2. Triggering the correct event.
I'm not sure exactly on which object or which event to trigger, but my best guess is either suggestionClicked on either the TypeAhead object or the TypeAhead.Dropdown object. Second best guess would be click.tt.
I might be overthinking this.
If you really care about the reason behind this, it's because I need to test the functionality via Capybara/Selenium.
I've been browsing the source code on github for some insight.
Here is a step in my Capybara attempt. I feel like I'm getting close but it's not there yet.
steps.rb
Then /^I select result number "([^\"]*)" from typeahead$/ do |num|
find('.tt-dropdown-menu')
#within('.tt-dropdown-menu') do
page.execute_script %Q{$(document.activeElement).dropdown().trigger('suggestionClicked', $('.tt-dropdown-menu .tt-suggestion:nth-child(#{num})'))}
#end
end

Find which event/observer is changing element

I am working with Prototype JS framework and I have a form with two select fields (each with three options). There is an observer that changes the text of another element whenever I select a value, which is what it is supposed to do.
However, how do I find out what code is observing that event (the selecting of an option in the form) and therefore making the changes to the element? I've spent the past few hours trying to work it out to no avail.
Am I correct in thinking there is a way to get a stack trace to find out what code is observing that change? Or is there an alternative method to debugging.
Thanks in advance for any advice :-)
The simplest fix was a matter of finding where Event.observe was written in the JavaScript and tracing back.
The documentation was helpful: http://prototypejs.org/doc/latest/dom/Event/observe/

AngularJS changes to the $scope properties aren't reflected in the view without calling $scope.$apply

First here's a plunk: http://plnkr.co/edit/2gD0AB. This plunk doesn't seem to work correctly because $scope.$on("$viewContentLoaded") won't fire, but on my machine it works just fine and I hope you get the idea.
What I'm trying to do there is simply move field objects from $scope.fields to $scope.groupFields = [], $scope.listFields = [], $scope.dataFields = [] when dragging them to the appropriate droppable areas. I've manager to do this using jQuery UI and jQuery UI touch punch (just to be mobile safe).
If you drag an element from the fields box to the one of the empty boxes you'll notice nothing happens on the screen besides the field elements hanging around where you left them. But if do a console.log($scope.fields) in the drop event listener you'll notice that all of the field objects are correctly set inside each of the field boxes.
If you click the Add element button then you'll simply trigger console.log($scope.groupFields); and suddenly all the elements appear correctly in their corresponding boxes like intended in the first place.
After pulling my brains out and after searching the internet for some time I found out that $scope.$apply(), called in the drop event after the moveField function, actually fixes my issue.
And I don't understand why. Shouldn't there be a digest already running and updating the view based on what I'm doing in the controller?
Thanks!
Just because the code that handles these jQuery drop events is inside the controller, it doesn't mean it will run under the angularjs scope/word. For those changes to make effect, you will need to force the angularjs app to do a dirty checking on its models. That can be accomplished by calling $apply() or $digest() methods. You should always call one of these methods after handling an jQuery event that changes $scope properties or after a timeout (or interval).

Facebook JS (FBJS) event listener

So I have looked through most of the facebook questions here and it has absolutely confirmed my thoughts. Facebook development may be among some of the worst I've ever used. I'll avoid my rant for now, but as a note to where I'm coming from: tried php sdk, worked decently out of the box, found out I need to put the functionality on a pages tab, can't iframe on pages tab, have to use FBML (which they are retiring in two months, yet I can't start testing the iframe approach yet)
Anyway, I run into FBJS at this point. It works "good enough" for most things, but for some reason I can't get an event registered to an object (a select box in particular interest) by adding a listener (as per FBJS documentation). I am able to add it directly to the html object and have it work, but this is not desirable and I would really like to know what I consider the proper way to do it, which involves seperation of logic and display.
What I want to happen: click on the select box, make a selection, display the text of the selection in an empty div (later on adding Ajax but one step at a time here)
Code:
<script>
var obj = document.getElementById('select-id');
obj.addEventListener('onchange',my_func);
function my_func(evt){
var inner = document.getElementById('div-id');
inner.setTextValue('hey'); // for testing purposes
}
</script>
The above code doesn't do anything when I make a change to the select box. However, this behaves as planned:
<select name="find_state" id="find_state" onchange="my_func();">
I will be grudgingly using this method as I develop, but would really love to know what I might be doing wrong or if anyone else has this issue? And if anyone has any opinions on the matter I would love to know of some form of facebook development recommendations as applications, pages, and tabs all appear to behave totally different from eachother, yet it seems that they all should be doing the same thing to me? Is there any unified way to develop across all three of these things, or am I missing something?
Thanks in advance, as well as for the past help!
I think it should be:
obj.addEventListener('change',my_func);
(instead of onchange)
Straight from Facebook documentation:
The third parameter [to addEventListener], boolean useCapture is required (it does not have a default value)
That means that you should have:
obj.addEventListener('change', my_func, false);
Use the following html and your events attached with .addEventListener() start to work. This seems to be undocumented "feature".
<select name="find_state" id="find_state" onmousedown="return true;">
This also enables the event to fire first time the user changes the value of select. Otherwise it would fire only on second onchange event.

Categories