I get an application and when I modify my bd, view Angular does not change.
I tried using $scope.$apply().
If you can help me, thanks a lot !!
$scope.modifyTask = function(id){
todoService.modifyTodos(id);
}
<i class="ion-android-checkbox-outline-blank caseACocher" ng-click="modifyTask(data.id)">
By cons, if I reload the page , it's ok. But I would not need to reload the page
There are many things that could be happening. Two things off the top of my head are:
You could be returning a promise from todoService and not resolving it.
id might be getting changed outside the scope, thereby $scope.apply will need to be invoked, like you said
You don't seem to be binding anything to $scope.id. You'll need to bind the DOM element to scope in order for it to reflect on your view
Related
I am new to knockout, so going to fire a lot of questions. But I'm not new to data binding. So I am knocking my head on the difference between my expectations and reality. Here is a very basic question about applyBindings.
It looks like applyBindings has the parameter "view model", which is to me the domain object graph (as javascript objects) plus perhaps additional helper things added for the purpose of the view creation. But what I am completely missing at first is the scope of the bindings! I expected this to be applied to the current parent DOM element. But no, it is applied globally, in the entire page!
So is the expectation that in one HTML document there can only ever be one view model? This is very surprising to me! How am I supposed to create a single page web app where I have one panel showing the address book, another panel showing my appointments, another panel showing one loan application to review, and yet another showing the underwriting of another loan? They are all completely different things, am I really supposed to link them all into a single view model???
In my expectation, you bind a javascript object to a DOM element, and everything in there renders it. With every new nested DOM element, the focus object may change. It may be flowing out of some foreach binding from the parent's object. But then two sibling (or cousin) DOM elements might be sitting side by side and having completely different view model, and also a different life cycle. Like while I am in my underwriting workflow, I quickly need to bring up an address book or my calendar. All of it in a single page app. There should be no global interference between different view models used by different unrelated DOM elements.
And yet here we are with knockout I see it has only one ko.applyBindings(viewModelObject) for a the entire page.
What am I missing? What is preventing us from modifying ko.applyBindings to take two arguments, the view model-object and the DOM element in which to show it? I could try doing that, but I am afraid if knockout has been designed in this global mindset, there might be lots of issues running the knockout machinery more than once on the same page?
I'm sorry if I am frustrating people by shooting an answer already. But since I have a very urgent project I need to try to resolve my issues ASAP, and I am reading the knockout source code, which is quite nicely organized and uses good names, so it's quite intelligible; therefore I have found the answer myself.
The answer is that, yes, you can applyBindings to a parent element that you choose. The document.body is only the default if you don't say anything.
Therefore, from now on, I shall (tell my team to) always call applyBindings with the second argument specified for the rootNode. Like this:
<div>
... all my UI elements for this thing ...
... then last element in this div:
<script type="text/javascript">ko.applyBindings(viewModelObject, document.currentScript.parentElement);</script>
</div>
so, that way I can have multiple view models each in their own DOM element.
And additionally also, I was wondering, does knockout not somehow assign the model object to the DOM element? I could do that in my script tag too:
<div>
... all my UI elements for this thing ...
... then last element in this div:
<script type="text/javascript">
const viewElement = document.currentScript.parentElement;
viewElement.viewModelObject = viewModelObject;
ko.applyBindings(viewModelObject, viewElement);
</script>
</div>
and this allows me then -- if only for debugging -- to find the current view model object on the DOM element that is the root of a view. (It would be nice if that would happen with all other descendant bindings too, but that is perhaps the subject of another question.)
In fact, I decided to put into our general configuration a hard replacement of the ko.applyBindings function:
ko._applyBindings = ko.applyBindings;
ko.applyBindings(viewModelObject, rootNode, extendContextCallback) {
rootNode = rootNode || document.currentScript.parentElement;
rootNode.viewModelObject = viewModelObject;
ko._applyBindings(viewModelObject, rootNode, extendContextCallback);
}
now I don't even have to convince my team to do it this way, they will automatically, even without being aware of it.
Currently, the website I'm working on uses knockout for our frontend framework. I want to incorporate Turbolinks with multiple knockout viewmodels across different pages. The problem I'm running into is that since turbolinks doesn't actually change the page, bindings get applied multiple times which results in an error.
So far here is what I have tried.
I found this article which describes exactly what I want to do but doesn't necessarily work.
His solution is to replace the ko.applyBindings with
window.applyTurboBindings = function(node, viewModelAccessor) {
return $(document).one("page:change", function() {
return ko.applyBindings(viewModelAccessor(), node);
});
};
and use it with this
applyTurboBindings(document.getElementById('my-node'), function() {
return new MyViewModel();
});
page:change is no longer a method used with turbolinks according to their documentation. So I tried it using turbolinks:load (which fires once after the initial page load, and again after every Turbolinks visit) and turbolinks:visit (fires immediately after a visit starts). That wasn't working either. The event never gets triggered when I call the method applyTurboBindings so no bindings get applied.
Here is a fiddle with a basic setup of what I'm doing. fiddle
When I run this through my debugger, the applyTurboBindings never catches the event (turbolinks:load) that is firing.
One idea I had was to use something like this:
$(document).one("turbolinks:load", function () {
// execute all js for page here
});
instead of the typical
$(function(){
// execute all js for page here
});
But I couldn't get that working either because bindings were still getting applied multiple times.
So my question is how on earth do I get this working for multiple viewmodels so the bindings don't break? Should I be organizing my js differently? Is there a simple solution I'm not seeing or is this just not a good idea use both together?
This is my first question on Stack Overflow by the way so if I'm missing anything or I didn't make my question clear enough please let me know. Thanks for your help.
I'm working on a directive I hope to make public for use and ridicule, and I've found a pretty major issue I can't figure out if its my controller code or my directive.
I have a variable I pass to the directive via '=' in the isolate scope. If I pass the variable as a child object of an object, it works perfectly in any case, but when I pass it a top level variable, it works in one case, any changes the directive makes are reflected in the parent scope, while in the second, any changes the directive makes are not seen in the parent
In the working case, I don't define the variable before it gets sent to the directive. It's modified in the directive, and shows up properly in the parent scope.
In the non-working case, it is defined before being sent to the directive, but none of the changes in the directive show in the parent scope.
In both case, I tried both predefining and removing any initial definitions of the variable being sent to the directive; in the working case, it continued to work, in the non-working case, no progress was made.
This is the first time I've seen a '=' scoped variable not change based on changes made in the directive, and I'm at a loss.
Unfortunately, I don't have a working case to show you. I put the code into a plnkr to show a co-worker, and you can see all my code to see if there's something stand out wrong, and while I'll try to put together a working case, it involves an API, a bunch of code around it, and I suspect my simplifying it to make a working plnkr will solve the problem and not help figure out the issue I'm having. Unfortunately, I don't even know what code I should show you directly, as SO only lets me link plnkrs if I have code here.
Basically I have a directive
<combobox data="dataList" value="result"></combobox>
Data can be sent in as an array of strings or an array of objects of this format: { 'value': 'car_3', 'display': 'BMW' }. Value returns as an object of the same type (if an array of strings is passed to data, its converted to objects in that format).
In case 1, result comes back with the data the directive sets, in case 2, it never changes (it maintains it's initial value.
http://plnkr.co/edit/hUCuZuBu9BUbdwD0V6AO
In the plnkr, main.js contains my directive, and both case files show how the directive is called in the HTML. I'm sure there's some junk code in there, as I've been debugging this like crazy...
hmm without seeing your code it sounds an awful lot like you're dealing with the common (super frustrating!) problem of js primitives being duplicated inside of child scopes, causing an unexpected non-bi-directional chain of binding. Are you using dot syntax on your model to force prototype?
Check out:
"Not having a dot in your ng-model (or other places you need it!)"
http://nathanleclaire.com/blog/2014/04/19/5-angularjs-antipatterns-and-pitfalls/
I'm building a directive that utilizes an ng-if inside of it's template. What's strange is that the element provided to the link function does not have the ng-if code expanded, it is only a comment line for the ng-if. Playing around, I found that by wrapping my link code in a $timeout seems to get it to work, but I am wondering if that is not the correct way of going about it....and more so, why is this happening.
I've added a plunk to demonstrate: http://plnkr.co/edit/Gl7v8yJLevi664nUKcFY?p=preview
Most directives actually do most of their logic in a $watch(). For example ng-if will setup a watch on it's attribute, and then render/remove the dom when that changes. Watches execute during a digest cycle, so even though directives have been compiled and linked, the watch hasn't run yet to determine whether it should show the if or not.
EDIT:
You should probably think about what you are actually doing to make sure if it's what you want. Keep in mind that the ng-if is dynamic. And so at any time it might get removed or added based on whether the items array is empty or not.
This means that even if you manage to defer your dom manipulation until after the if is rendered, you run the risk of the if going away and coming back (at which point your css code will not be run again).
A much better way to do this would be to setup a watch and add your css in a watch, or better still, use ng-class and add the css in your template.
The angular framework needs to have $scope.$apply() called in order to update the bindings and expand the template. $timeout() is an async wrapper which assumes that changes were made outside angular world and it calls $scope.$apply() as a final step. in your case, using $scope.$apply(); directly, immediately before your element call achieves the desired effect.
I have already read the
Compilation process, and directive matching
on AngularJS Doc.
but I really didn't understand the directives.
Example:
I have static html:
<div class="test test2" cid="549" sid="a5e3c4f8a9">text-text-text</div>
when I do it manually, I know it will only created and called one time at browser's parse time.
but what happens when I create a directive with the same dom element ?
<x my-directive>text-text-text</x>
is this the same effect?
I am asking such a newbie question, because I am using over 200 elements on my html page.
If I change them to single directive: for sure it will be much more easier to manage them.
and its no problem if its only slow at browser's compile time but what happend in run time?
and I am sorry, if the qustion is not pro enought. I am just new to Stackoverflow.
Thank You
Daniel
If I understand you correctly, you want to know how AngularJS creates a directive and how many times your directive methods are called.
When you create a directive (with module.directive('myDirective', ...)), you are really just creating a definition. Every time you use that directive (like <div my-directive>), AngularJS will run through the process described in the guide: that is, it will compile and link each use. It has to be this way because the directive doesn't exist in isolation; it exists not only in the $scope in which it was called, but also it can make use of element attributes and transcluded contents. The definition occurs once, but each instance is compiled and linked.
Once the directive is created, it's technically done; if you don't set up any $watch or $observe or event bindings, your "directive" is now just whatever's in the DOM at the end of your link function - there's no more computation. In other words, what happens after compilation and linking is entirely up to you.
So back to your example: if you use 200 of the same directive on the page, the directive will be defined once, but all 200 will be compiled and linked separately. But I'm not really sure what you're implying by asking. What's the question behind your question?