On second time I tap button I do not have value anymore. How to Load variable on every app load. The variable I am talking about is changing since it is always textField.text! and it is user input. I use it when user taps LocalNotification action, app opens and then function triggers like this:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "someFunctionWhereIsMyProblematicVariableINeedToLoad:", name: IDENTIFIER, object: nil)
How to stick the variable every time user enters it, into local notification. Are every notification somehow different or just text changes?Are there any ID-s to make every notification special?
LocalNotificationHelper.sharedInstance().scheduleNotificationWithKey("someText", title: "see options(left)", message:textField.text!+"someText", date: deadlinePicker.date, userInfo: userInfo)
I need that textField.text to be in this variable: let predicate = CNContact.predicateForContactsMatchingName(textField.text!)
I tried to store them into NSUserDefaults and into arrays and loop through arrays to find if value exists etc. But It works only first time and second time it is nil
Edit: It keeps only the last entered value as variable. How to keep them all?
Here I show you in the pictures what I tried to explain with words:
Now if blue button is tapped I start function where I need to use the "firstTimeEntered" as variable but at the second notification it is"SecondTimeEntered"
Variables class scope:
var sentence:String = ""
var firstWord = [String]()
var firstWordAsString:String = ""
Function "A":
sentence = textField.text! + " needs to be deleted from array."
var firstWordAsString = sentence.characters.split(" ").first.map(String.init)
firstWord.append(firstWordAsString!)
defaults.setObject(firstWord, forKey: "firstWord")
let userInfo = ["url" : "Hello"]
//Set notification
LocalNotificationHelper.sharedInstance().scheduleNotificationWithKey("someText", title: "see options(left)", message: sentence, date: deadlinePicker.date, userInfo: userInfo)
Function "B":
defaults.objectForKey("firstWord") as? String
if contacts.contains(firstWordAsString){
let predicate = CNContact.predicateForContactsMatchingName(firstWordAsString)
This is ultimately an issue of scope.
//This is the largest scope called the global scope. anything available here is available anywhere in your application.
class myclass {
//this is the class level scope any variables here would be available from within the class but not outside of it. I can use any variables in the class scope or the global scope.
func myFunction() {
//this is the function scope, any variables here would be available from within the function but not outside of this function. I can use any variables in the class scope, global scope and my own scope.
}
func mySecondFunction() {
//this is also the function scope, I can have my own variables but I cannot see the variables in myFunction()
}
So if you were to put a var savedValues = [String]() at the top of a function it would not be available from another function. but if you put the same in the class scope, it would be available in both functions. Each time a function starts, it will define the function variables and when it exits itself, the variables are removed from memory.
to solve your issue put an array of strings within your class, and then use the append method of that class level array to add new things to it. you could then search against that array by using the filter method or looping though it.
Related
I have the prerequisite setup...
define([ "dojo/_base/array", array ...
I create my array "concats" in the "return declare([], { concats: [], ..." area. There is a method/function called _createForm: function (fields) { ...}
Inside of this function I have : this.concats = [];
Inside of _createForm is a call to another method/function called : _createFormElement and inside of there whenever I try to PUSH to this.concats I get
"TypeError: Cannot read property 'push' of undefined"
I've tried every conceivable method to add items to this array but nothing I do, short of including this.concats = [] in the _createFormElement function will let me. AND if I include this.concats = [] in the _createFormElement function then it erases the array...
So sure, it holds ONE object, but I need it to collect objects for each Form Field in a global-ish array.
I'm so confused.
So it turns out I just have to reference the "global" (but not really global) array variable like so in my _createFormElement function/method...
var myVariable = this.concats;
Then in that function I can push like so...
myVariable.push(itemToPush);
I have a tableview bound to a NSArrayController. The ArrayController gets it´s data from an array [NSObject]:
class Fruits : NSObject {
var name:String
var price:Double
// If I set 'isBold = true' here manually,
//the font in my tableview becomes bold (from start of the application).
dynamic var isBold = false {
didSet {
print(isBold)
}
}
override init() {
name = "name"
price = 0.0
}
init(name:String, price:Double) {
self.name = name
self.price = price
}
}
So everything works fine as long as I set the ìsBold`value manually.
If I call in ViewController:
Fuits.init().isBold = true
tableView.reloadData()
The correct ìsBold`value is printed, but in the tableview nothing changes. Any ideas why the ArrayController doesn't notice the updated value?
EDIT:
I found a way how it is working. But maybe just a hint why it is not working like above. This solution works with iteration, I don´t think it is how it's supposed to be.
func changeBold(bold: Bool) {
if bold == false {
self.dataArray.forEach { fruit in
fruit.isBold = false
} else {
self.dataArray.forEach { fruit in
fruit.isBold = true
}
}
}
Edit: I misinterpreted what you had written. I thought the bindings settings panel was for the table view, not the table cell view. The rest of what you wrote makes more sense to me.
Your line Fruits.init().isBold = true is a bit odd syntax-wise, but the bigger point is that you're creating a new instance of Fruits and setting its bold attribute but not doing anything with the instance, so it goes away once it's out of scope. You need to change the property of the instance stored in the cell view's objectValue property (because that's the instance that's set by the bindings mechanism, which your cell view represents).
Also, be aware that "editing an object behind the controller's back" will also usually cause the symptom of changes not appearing in the UI. Example: if you remove an instance of Fruits from your array directly, you'd have to tell the array controller to refresh to see the changes (which can lose selection and scroll information in a table or some other UI state). Instead, you should access the array controller's arrangedObjects property and remove / add / insert there so the array controller is "aware" of the changes. You'll need to read a lot more on the bindings mechanism to understand when / why to make changes through a controller vs. directly, but it's an aspect of Cocoa Bindings of which you must be aware.
I am facing a very strange issue with variable in one controller being hijacked by another controller. Here are the details:
In my HTML I have two ng-view tags. Each tag leads to a templateURL (an html) that has its own corresponding controller. Ctrl1 and Ctrl2
the two ng-views are at the same level in the html hierarchy - that is, one is NOT the child of another
Controller1 looks like this:
ngEpMod.controller('Ctrl1',[function() {
selfX = this;
abc = 'abc controller1';
console.log(abc); // break point 1
selfX.query = function() {
console.log("abc=");
console.log(abc); // break point 2
console.log("search query=");
console.log(selfX.searchQ);
lySP.searchHomes();
};
}]);
Controller2 looks like this:
ngEpMod.controller('Ctrl2',[function() {
self = this;
abc = 'abc controller2';
}]);
Both controllers are associated in the html using a "controller as" syntax.
The query() method in Ctrl1 is fired when user user clicks a button (ng-click)
Mystery: As I load the html page ($state) that has the two ng-views, I am observing the browser console. I note that abc value at break-point1 is "abc controller1", but when the query() method is fired, it mysteriously changes to "abc controller2". There is no global variable by that name! As I understand, when the page is being laid out, Ctrl1 is created first so at break-point 1 abc has the correct value, then Ctrl2 is created and somehow it high-jacks the abc variable! Stranger even is that I noticed this problem first with my self variable (self = this) and then I introduced abc just for additional check
Gurus, I am a newbie and would really appreciate your help.
By creating a variable without var (or let in ES6), you've created a global variable attached to window:
abc = 'abc controller1'; equals to window.abc = 'abc controller1';
When the 1st controller instantiates it declares the variable abc on window. When the 2nd controller instantiates, it changes the global abc variable content.
To avoid it in this case define var abc in both controllers.
To avoid it in the future add 'use strict'; to each function deceleration, for example:
ngEpMod.controller('Ctrl2',[function() {
'use strict';
self = this;
var abc = 'abc controller2';
}]);
Strict mode will throw error when you make this mistake (any many others). From MDN:
First, strict mode makes it impossible to accidentally create global
variables. In normal JavaScript mistyping a variable in an assignment
creates a new property on the global object and continues to "work"
(although future failure is possible: likely, in modern JavaScript).
Assignments which would accidentally create global variables instead
throw in strict mode:
I would drop the below code into your app above this instantiation (most modern browsers should understand this syntax for debugging). Call window.trackCtrl in every controller constructor and then pop open the console in chrome or firefox and type printCtrls() and you should get a print out of when they were created in order.
window.trackCtrl = (name) => {
var newCtrl = {}
newCtrl.name = name + '_' + performance.now()
window.trackingCtrls = window.trackingCtrls || []
window.trackingCtrls.push(newCtrl)
}
window.printCtrls = () => Array.isArray(window.trackCtrls) ? window.trackingCtrls.forEach(x => console.info(x)) : console.error('trackCtrls not defined')
This will find bugs such as the controllers getting loaded out of order or duplicate copies of your code or libraries getting loaded on the same page. Performance API helps a lot in these situations => https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
I got a service that contain some contacts (name,phone). The controller has array that contain a reference to the array from the service so for every change on the array all gets updated.
Service:
app.service('ContactManagerService', function()
{
this.Contacts=[];
...
this.AddContact=function(Contact){...};
this.RemoveContact=function(Contact){...};
...
});
First question: Is this a good approach? Should every controller/directive need to have a direct reference to the original array from the service? I have read a lot about setting up some events from the service to the controllers when the array has been changed, but it sound stupid because the array on the controller will be change anyway (because its the same array) and the ng-repeat will be updated automatically.
Second problem: The service has a method that replace the array to new one:
this.ReplaceContacts=function(NewContacts)
{
this.Contacts=NewContacts;
});
The ng-repeat does not update because the controller still got the old reference to the old array. So a refresh need to be done.
I tried to replace the code to this one so the same array's reference wont change, but when the the code enter the foreach, this.Contacts array is undefined and the code stops. Why ?!
this.ReplaceContacts=function(NewContacts)
{
this.Contacts.splice(0, this.Contacts.length); //remove all contacts
NewContacts.forEach(function (contact, index)
{
this.Contacts.push(contact);//place the new ones
});
});
The controller code:
app.controller("myCtrl",
function ($scope,ContactManagerService)
{
$scope.Contacts = ContactManagerService.Contacts;
$scope.AddContact= function (Contact1) {
ContactManagerService.AddContact(Contact1);
}
$scope.RemoveContact = function (ContactID) {
ContactManagerService.RemoveContact(ContactID);
}
});
I hope everything is clear,
Thanks.
Because the callback function passed to forEach isn't bound to the service instance. So this, inside the callback, is not the service.
My advice: avoid this like the plague. It's an enormous source of bugs in JavaScript.
Use
var self = this;
at the top of the service, and use self instead of this everywhere.
Or bind the callback function to the service instance:
NewContacts.forEach(function (contact, index) {
...
}, this);
You can simply push elements to Contacts using Array.prototype.push()
The push() method adds one or more elements to the end of an array and returns the new length of the array.
this.ReplaceContacts=function(NewContacts){
this.Contacts.splice(0, this.Contacts.length); //remove all contacts
Array.prototype.push(this.Contacts, NewContacts);
});
As mentioned in previous anser, context of this in forEach loop is not what you think it is.
A simplification would be to use Array.prototype.concat():
var self = this;
self.ReplaceContacts = function (NewContacts) {
self.Contacts.splice(0, this.Contacts.length); //remove all contacts
self.Contacts.concat(NewContacts);
});
i have something like
Ext.define('HS.controller.Utility', {
statics : {
state : 'Oklahoma'
}
});
Now i want to access it from my controllers, but in every method of controller, i have to write HS.controller.Utility.state to access it. currently i'm doing this : var ut = HS.controller.Utility and then accessing state as ut.state, but again, i've to declare this variable in every function. Is there a way to set it to a short name once in my controller and then access from all functions?
There are several ways you could do it, the best of which:
// Becomes a global variable
var X = Ext.define('My.long.class.Name');
// Set a reference on your main NS at launch time
launch: function() {
MyApp.X = My.long.class.Name;
}
Even easier than the current answer is to just declare an alternateClassName with no namespace. Only one line of code, no initialization or race conditions, built into ExtJs.
Ext.define('HS.controller.Utility', {
//
// Non-namespaced alternate class name will create
// 'globally defined' Utility object.
//
alternateClassName: 'Utility',
statics : {
state : 'Oklahoma'
}
});
});