How can I change a scope variable using the on-scroll event in Ionic? - html

I want to change value of a variable when the value of scroll position is greater than 100 from top but it doesn't work, the value doesn't change in $scope.
Here is the code:
<div ng-show="title===true">
<p>{{title}}</p>
<p>{{card.nome}}</p>
<p>{{card.prezzo}}€</p>
</div>
<ion-content style="top:0px" delegate-handle="cardScroll" on-scroll="getPositionScroll()">
$scope.title = true;
$scope.getPositionScroll = function () {
console.log("scrollPosition " + JSON.stringify($ionicScrollDelegate.$getByHandle('cardScroll').getScrollPosition().top));
console.log("valore title " + $scope.title);
console.log($ionicScrollDelegate.$getByHandle('cardScroll').getScrollPosition().top >= 100);
$scope.title = $ionicScrollDelegate.$getByHandle('cardScroll').getScrollPosition().top >= 100;
};
Does anyone know why this is not working?

I think it may have to do with the fact that Angular doesn't track changes that have been made by the getPositionScroll() function. A lot of Angular functions are wrapped in the $scope.$apply() function which notifies Angular about changes that have been made. But I think that the function used to track scrolling is not wrapped in this function, which means that you need to call it yourself.
So after $scope.title add:
$scope.$apply($scope.title);
There are a lot of questions regarding when to use $scope.$apply(), like this one, if overused it can cause serious harm to the performance of your app. There is also information about this in the Angular documentation. You may also find some insight in this question about when to use this function in a scroll event.

Related

*ngIf or [hidden] not working correctly

I'm trying to allow for hiding of certain sections of the project I'm working on via user toggle. It saves in the database and gets pulled when the page is loaded in the constructor using the following code
this.http.get(`api/section/get/${this.id}`, this.id).subscribe(res => {
this.section = res.json()[0];
this.sect = res.json();
console.log(this.section);
this.hideIntro = this.sect[0].hideIntro;
this.hideMainVideo = this.sect[0].hideMainVideo;
this.hideHandout = this.sect[0].hideHandout;
this.hideQuiz = this.sect[0].hideQuiz;
console.log("Hide Intro = " + this.hideIntro);
console.log("Hide Main = " + this.hideMainVideo);
console.log("Hide Handout = " + this.hideHandout);
console.log("Hide Quiz = " + this.hideQuiz);
});
The HTML is as follows...
<div class="row classMainBackground col-md-12" *ngIf="!hideIntro">
...content...
</div>
For some reason, no matter what I do, whether I change it to *ngIf="hideIntro == false" or even use [hidden]="hideIntro", it is not working.
Even the console logs in the .ts file show up correctly. Is there a reason why this is not working for me? I've used it in other positions and it works fine there...
Does it have something to do with assigning it in the constructor or something?
Thanks in advance!
Angular change detection runs in response to use interaction with the component. If values are updated outside of that event handling (such as after an HTTP request), you need to manually tell the component that it has changed.
constructor(private changeDetector: ChangeDetectorRef){}
this.http.get(`api/section/get/${this.id}`, this.id).subscribe(res => {
[...]
this.changeDetector.markForCheck();
})
More in depth reading: https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
I ended up solving the problem by using {{!section.hideIntro}} in the HTML instead of trying to define a new variable to pass that boolean to.
I believe the answer was a combination of what #Vlad274 and #ConnorsFan were mentioning.
the HTML was returning an [object object] for {{hideIntro}} and it seems like there's a delay between the assigning the new value data from the GET response before the DOM actually loads.
Grabbing the data right from the GET respone variable ended up doing the trick.

detecting and hiding dynamically creating div after a specific seconds (not onclick)

i have a dynamically generating div which is not in the time of loading. It is generating later in the document. So how can i target that div and hide it after specific time. The div is as follows:
<div class="message-sent">Your Message has been sent</div>
Important: I refer so many articles but everyone is talking about 'onclick'. I don't want click event. I just want hide this div when it is appearing in the docuemnt. Thanks in advance!
you can add a style display:none.
you can add the style after time out (3000ms) like so:
setTimeout(function(){
document.getElementsByClassName("message-sent")[0].style.display="none";
}, 3000);
note: it is better if you use an id instead of a class to identify your div.
You should try looking into the setTimeout function.
Also if that div is the only member of the DOM-tree that has that class, use an ID. It's better IMO.
Anyway, assuming you want to hide every member of the message-sent-class,
it goes something like this:
setTimeout(function(){
$('.message-sent').hide();
}, 2000)
In which the 2000is the variable that indicates the time (milliseconds)
You can try DOMNodeInserted,
$(document).bind('DOMNodeInserted', function(event) {
var element = document.getElementsByClassName("message-sent"); // get all elements with class message-sent
var lastchild = element[element.length - 1]; // get the last one (others are hidden)
if(lastchild != null){
lastchild.style.visibility = 'hidden'; // set visibility to hidden
}
});
Working demo
Hope helps,

How to dynamically add text to textarea while recording via webkitspeech with Angular 2?

Currently, I record my voice with this simple code in Angular Component
speechToText() {
const {webkitSpeechRecognition}: IWindow = <IWindow>window;
const recognition = new webkitSpeechRecognition();
recognition.lang = 'en-US';
recognition.continuous = true;
recognition.interimResults = true;
recognition.onresult = event => {
for (let i = event.resultIndex; i < event.results.length; ++i) {
this.interim_transcript = event.results[i][0].transcript;
}
};
recognition.onerror = event => {
console.log('Error occured', event);
};
recognition.start();
}
}
And in my HTML I have the value bind to the interim result
<textarea #description mdInput rows="5" placeholder="Short Story" name="description" [value]="interim_transcript"></textarea>
The problem, however, is that I can see the text being put into the textarea only after I click on the textarea or outside of it to trigger dom update. How to make it update textarea as soon as I begin saying words giving this live text update, same way as here https://www.google.com/intl/en/chrome/demos/speech.html
This happens because Angular is not aware of the update to interim_transcript since it happens outside of what the Zone is aware of.
I see two immediate ways to fix it:
Run the interim_transcript update in a zone.run call. See NgZone in the docs.
Make interim_transcript an Observable. Actually a Subject, but the point is that it needs to be observable.
I'd recommend the latter, and it basically involves this:
When you define interim_transcript, define it like this: interim_transcript: new Subject<string>()
When you update it in the onresult callback, replace
this.interim_transcript = event.results[i][0].transcript;
with
this.interim_transcript.next(event.results[i][0].transcript);
Change the value binding in your template, replace:
[value]="interim_transcript"
with
[value]="interim_transcript | async"
Observables are an incredibly powerful concept that can make your code more easy to reason about (even though it seems very odd at first). It can boost your performance significantly when you start using the OnPush change detection mechanism. Finally, however cheesy it sounds, can change the way you think about your programs, to a data stream mind model instead of state updates. This will likely sound confusing and weird, but I strongly recommend looking into it, I'm sure it will pay off.
Here are a few good resources to get started:
Using Observable from Rangle.io.
Understand and Utilize the Async Pipe in Angular 2 from Brian Troncone

Can I force the increment value on scroll for dijit.form.NumberSpinner?

I'm using the dijit.form.NumberSpinner() widget in a form for looking up indexed content. This works great in most cases—entering a number, using the arrow keys, and using the spinner buttons all respond in the right manner. However, on some browsers (notably Firefox), using the scroll wheel over the field increments the value by something > 1.
Is there a way to force the scroll increment on such a number field to be 1 across all browsers? The +3/-3 behavior is strongly undesirable for my application as the results are scrolled through in real time as the value is updated.
I am already using a custom widget derived from NumberSpinner so adding or over-riding a property should not be difficult if that is what is required, I just don't know what to change. The docs only say the increment should be 1 for arrow keys, they don't say anything about scrolling.
That's because it depends on what the event itself provides (= given by the browser). Currently it uses either the evt.wheelDelta or evt.detail property from the mousewheel event to determine the increment value. However, there are no standards yet and most implementations are using certain functions to normalize the scrolling speed.
If you use the following code in Firefox:
require(["dojo/ready", "dojo/mouse", "dojo/on", "dijit/registry", "dijit/form/NumberSpinner", "dojo/parser"], function(ready, mouse, on, registry) {
ready(function() {
on(registry.byId("mySpinner").domNode, mouse.wheel, function(evt) {
console.log(evt.detail);
});
});
});
It will show you that this value is 3 or -3 when executed in Firefox.
If you really don't want it to depend on what the browser says, you can override the _mouseWheeled function:
FixedNumberSpinner = declare("dijit/form/FixedNumberSpinner", [ NumberSpinner ], {
_mouseWheeled: function(/*Event*/ evt){
evt.stopPropagation();
evt.preventDefault();
var wheelDelta = evt.wheelDelta > 0 ? 1 : -1;
var detailDelta = evt.detail > 0 ? -1 : 1;
var scrollAmount = evt.detail ? detailDelta : wheelDelta;
if(scrollAmount !== 0){
var node = this[(scrollAmount > 0 ? "upArrowNode" : "downArrowNode" )];
this._arrowPressed(node, scrollAmount, this.smallDelta);
if(this._wheelTimer){
this._wheelTimer.remove();
}
this._wheelTimer = this.defer(function(){
this._arrowReleased(node);
}, 50);
}
}
});
But please remember that the implementation might still change in the near future, so personally I would just stick with the increment of 3.
A full example can be found on JSFiddle: http://jsfiddle.net/4ZQTY/5/
EDIT: As mentioned in the comments, an even easier solution would be to override the adjust() function.
In most cases it is best to leave the behavior of such widgets alone. The mouse wheel action taken will be familiar to the users of each browser as the stock input widgets respond the same way.
In the event that over-riding this does make sense, you can tweak the adjust() method of the dijit widget. If you want to force the widget to step through every intermediate value no matter size adjustment was requested, you can force the delta value to be 1, then proceed with the contents of the original function.
adjust: function (val, delta) {
delta = delta > 0 ? 1 : -1;
return this.inherited(arguments);
}
(jsfiddle)
Thanks to Dimitri M's answer for putting me onto the hunt, but I found overriding the value in adjust() to be simpler than re-defining _mouseWheeled().

how do I display a variable w/ jquery?

This is a fairly newbish question, so apologies in advance.
I want the scrolltimes variable to update each time the user scrolls the page. I've tried a half dozen different ways and can't quite figure out how to make the variable show up. I've managed it w/ append/prepend, but that doesn't remove the old version... do I need to remove the previous version and add in the new one each time or is there a way I can display the <p>Scrolled: N</p> substituting the value of scrolltimes for N?
Script:
var scrolltimes = 0;
$(document).ready(function() {
$('#clay').scroll(function() {
$('#scrollamount p')
.html({'<p>Scrolled: '+ .scrolltimes++ + '</p>'});
});
html:
<div id="clay" style="height:100px; overflow:scroll;">
<div id="scrollamount">
<p>Scrolled: 0</p>
</div>
<p>Pretend there is lots of content here</p>
</div>
You have a few syntax errors in your script. Try this:
var scrolltimes = 0;
$(document).ready(function() {
$('#clay').scroll(function() {
$('#scrollamount p').html('<p>Scrolled: '+ ++scrolltimes + '</p>');
});
});
The errors were:
Closed the scroll event function, but not the ready function - I added a }); to the end
Unnecessary dot at the beginning of the scrolltimes variable - I removed the .
Don't need to put the argument to the html call in an object - I removed the { and }
In addition to that, in order to make your output correct, I moved the increment on the scrolltimes variable from post-increment to pre-increment. Thay way the variable gets incremented before it is shown and now the first scroll event shows 1 instead of 0. The same thing could have been achieved by initializing var scrolltimes = 1;