Asked  7 Months ago    Answers:  5   Viewed   17 times

I remember seeing this famous quote from a video on AngularJS saying that should be always using a . (dot) in your models.

Well I am trying to follow this say I have

   var item = {}
   item.title = "Easy Access to support";
   item.available = true;
   item.price = 31.67;

So this works great in my view i do

  {{ item.title }}
  {{ item.available }}

I am using a dot so I think this is good.

But I have some properties that I don't consider part of the model but maybe I am wrong. For example I have a property I use to enable or disable a button using the ng-disable, I have entered this using dot format. Its basically entered like so

 $scope.disableButton = true;

and I use it like

 ng-disable="disableButton"......

Should I make this part of the model "item" ? or create another js object just so i can hold this property using a dot ?

Anybody know if this acceptable or should I be doing everything (even these simple properties) with a .dot ??

Thanks

 Answers

74

The "there should always be a dot in your model" refers to ngModel. This directive does two-way binding. If you two-way bind to a primitive (such as a Boolean in your case), the setter will set it on the current scope rather than the scope on which it is defined, which can cause a headache when you have a large user-interface with a lot of child scopes. It does not refer to other directives such as ngDisable. See this explanation for more details on this specific issue.

Sample scenario: a parent scope with $scope.foo = "bar", and a child scope with a <input type="text" data-ng-model="foo">. It will display bar initially, but once the user changes the value, a foo will be created on the child scope and the binding will read and write that value. The parent's foo will remain bar. Hope that summarises it well.

So for ngModel purposes, you might have to create an object to work around such binding issues, but for any other directive you should have the regular, logical grouping.

Tuesday, June 1, 2021
 
pop
answered 7 Months ago
pop
10

Don't use this pattern - This will end up causing more errors than it solves. Even though you think it fixed something, it didn't.

You can check if a $digest is already in progress by checking $scope.$$phase.

if(!$scope.$$phase) {
  //$digest or $apply
}

$scope.$$phase will return "$digest" or "$apply" if a $digest or $apply is in progress. I believe the difference between these states is that $digest will process the watches of the current scope and its children, and $apply will process the watchers of all scopes.

To @dnc253's point, if you find yourself calling $digest or $apply frequently, you may be doing it wrong. I generally find I need to digest when I need to update the scope's state as a result of a DOM event firing outside the reach of Angular. For example, when a twitter bootstrap modal becomes hidden. Sometimes the DOM event fires when a $digest is in progress, sometimes not. That's why I use this check.

I would love to know a better way if anyone knows one.


From comments: by @anddoutoi

angular.js Anti Patterns

  1. Don't do if (!$scope.$$phase) $scope.$apply(), it means your $scope.$apply() isn't high enough in the call stack.
Tuesday, June 1, 2021
 
Saurabh
answered 7 Months ago
21

Using your code structure, in your child controllers you would need to change:

$scope.$parent.kills++;

to

$scope.$parent.$parent.kills++;

Explanation: MainCtrl's scope is the parent scope of SimpleParentCtrl, but the grandparent of Step1Ctrl and Step2Ctrl. As some others pointed out, ng-switch creates its own scope, and then your Step1Ctrl and Step2Ctrl each created a child scope of the ng-switch.

Note: Each time the 1 or 2 button is clicked, both the ng-switch and it's currently matched child controller get a new scope.

Also: In case you happen to be looking in the Angular source and wondering how the ng-switch directive creates its own scope without a scope property, the answer is that it does so manually in its link method via scope.$new(). The directives ng-include, ng-switch, ng-repeat, and ng-view all create new scope this way, either in the link method or the compile method's returned link function.

Resources:

https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance http://www.youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m

Saturday, October 2, 2021
 
drowneath
answered 2 Months ago
68

It looks like your HTML string isn't properly formed.

Try this:

- (void)viewDidLoad {

    [super viewDidLoad];

    float width = 200.0f;
    float height = 200.0f;

    NSString *youTubeURL = @"http://www.youtube.com/watch?v=ZiIcqZoQQwg";

    UIWebView *webView = [UIWebView new];
    webView.frame = CGRectMake(60, 60, width, height);

    NSMutableString *html = [NSMutableString string];
    [html appendString:@"<html><head>"];
    [html appendString:@"<style type="text/css">"];
    [html appendString:@"body {"];
    [html appendString:@"background-color: transparent;"];
    [html appendString:@"color: white;"];
    [html appendString:@"}"];
    [html appendString:@"</style>"];
    [html appendString:@"</head><body style="margin:0">"];
    [html appendFormat:@"<embed id="yt" src="%@" type="application/x-shockwave-flash"", youTubeURL];
    [html appendFormat:@"width="%0.0f" height="%0.0f"></embed>", width, height];
    [html appendString:@"</body></html>"];

    [webView loadHTMLString:html baseURL:nil];

    [self.view addSubview:webView];

}

It's worth noting that this code will only work on a device, it won't work in the simulator.

UPDATE...

Due to changes made by YouTube, the method above is now incorrect. Use the method below instead.

- (void)viewDidLoad {

    [super viewDidLoad];

    float width = 200.0f;
    float height = 200.0f;

    NSString *youTubeToken = @"K95Q0VFyhA8";

    UIWebView *wv = [UIWebView new];
    webView.frame = CGRectMake(60, 60, width, height);

    NSMutableString *html = [NSMutableString string];
    [html appendString:@"<html>"];
    [html appendString:@"<head>"];
    [html appendString:@"<style type="text/css">"];
    [html appendString:@"body {"];
    [html appendString:@"background-color: transparent;"];
    [html appendString:@"color: white;"];
    [html appendString:@"margin: 0;"];
    [html appendString:@"}"];
    [html appendString:@"</style>"];
    [html appendString:@"</head>"];
    [html appendString:@"<body>"];
    [html appendFormat:@"<iframe id="ytplayer" type="text/html" width="%0.0f" height="%0.0f" src="http://www.youtube.com/embed/%@" frameborder="0"/>", width, height, videoToken];
    [html appendString:@"</body>"];
    [html appendString:@"</html>"];

    [wv loadHTMLString:html baseURL:nil];

    [self.view addSubview:wv];

}
Wednesday, November 10, 2021
 
Sarah Vessels
answered 4 Weeks ago
75

If your directive creates an isolate scope (and there are no intermediate scopes), and it uses = for two-way databinding, you don't need to use object properties – i.e., you don't need a "dot" to get it to work.

In Fiddle 1 and 2, ng-repeat is creating an intermediate (child) scope that prototypically inherits from the MyCtrl scope. In this case, you need to use object properties.

Sunday, November 21, 2021
 
cusejuice
answered 2 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share