Always getting not null object even though there are no objects with these parameters;


#1

I always get that object that I am returning is not null. My goal here is that when grades.get(‘firstObject’) === null to create new object. Its like it returns the object that exists no matter what are the parameters. Because I get the right student and subject in calling the alert order. Please tell me what is wrong. Here is the snippet of the code.

insertMark(val1, val2){ 
            var student = this.store.peekRecord(“student”, val1); 
            var subject = this.store.peekRecord(“subject”, val2); 
            var mark = this.get(‘mark’);

			alert(student.get('firstName') +  " " +  student.get('lastName'));
			alert(subject.get('title'));
			
			var grades = this.store.peekAll('grade');

			grades.find(function(item, index){
				const student2 = item.get('student');
				const subject2 = item.get('subject');
				if(student2 === student && subject2 === subject){
					return true;
				}
				return false;
			});

			if(grades.get('firstObject') !== null){
				alert("Object is null even though there is no object with those parameters. ");
			}
}

#2

Hi @komi94, I think you’re very close, the problem is a semantics one.

Let’s break down what I think is happening:

First, you’re doing a peekAll, this returns a RecordArray, which, even if there are 0 records will still be a non-null object of type RecordArray. No problem there.

Next, you’re filtering (I’m assuming that’s what the grades.find is doing at least), all good there. However note that if you filter all the records out you’re left with an empty RecordArray, that’s important in the next part.

Last you get to the part where you’re saying grades.get('firstObject') !== null which I think is the problem. What you’re doing here is getting the first object from a (in this case at least) empty RecordArray, and then strictly comparing to not null. However if you try to get the firstObject from a RecordArray, it will not return null, it will return undefined, and in javascript null and undefined are different values when using strict comparison. So essentially, undefined !== null, which evaluates to true.

To fix this you have several options. My personal choice would be to say:

if(grades.length) {
  // this will be evaluated if the the length of the array is anything other than 0, e.g. if there are any records in grades
}

because what you’re really doing is looking at length of the grades RecordArray. However if you still wanted to look at the first object you could either say:

if(grades.get('firstObject')) {
  // this will be evaluated if the firstObject is ANY truthy value, e.g. not undefined, not null, not false, etc.
}

or

if(grades.get('firstObject') !== undefined) {
  // this will be evaluated if the firstObject is strictly not undefined, e.g. if the record array is empty
}

Is there a way to check if some record exists before I create a new one?
#3

@dknutsen well I am even more closer now thanks to you! :slight_smile: But, there is still one bug. It’s like he filters the first subject correctly and every next time he still keeps reference to the same subject and insert the marks (that is grades) in that subject. Do you have any idea why? Here is my snippet of code, I would appreciate if you could look one more time… :slight_smile:

unesiOcenu(val1, val2){
			var student = this.store.peekRecord("student", val1);
			var subject = this.store.peekRecord("subject", val2);
			var mark = this.get('ocena');
			
			alert(student.get('firstName') +  " " +  student.get('lastName'));
			alert(subject.get('title'));
			
			var grades = this.store.peekAll('grade');

			grades.find(function(item, index){
				const student2 = item.get('student');
				const subject2 = item.get('subject');
				if(student2 === student && subject2 === subject){
					return true;
				}
				return false;
			});

			if(grades.get('firstObject')){
				grades.get('firstObject').get('marks').pushObject(mark);
				grades.save();
			}else{
				this.store.createRecord('grade', {
					marks: [mark],
					student: student,
					subject: subject 
				}).save().then(function(ocena){
					student.get('grades').pushObject(ocena);
					student.save();
					subject.get('grades').pushObject(ocena);
					subject.save();
				})
			}
		}

-My models, template and sample of firebase data are in this link: Is there a way to check if some record exists before I create a new one?


#4

@komi94 could you provide a little more detail on what’s going wrong? I’m afraid I don’t have enough context to understand. For starters, what do you mean by “every next time”? Is the function that you posted above (unesiOcenu(val1, val2){...}) getting executed many times? And if so what do val1 and val2 look like on consecutive executions?


#5

favor Ember.isPresent instead when checking for null;


#6

@dknutsen of course I will. So, this function unesiOcenu(val1, val2) works perfectly when I insert grade for the first time in that class for the first student (it doesn’t need to be first on the list) and some subject. But every next time when I try to insert grade in that class for other student from another subject or for that previous student from another subject it always insert grade from the subject I started with. Which is very strange because:

  1. Model class is not in relationship with model grade in any way, only with models student and subject; (Is there a way to check if some record exists before I create a new one?)

  2. I checked with alert order and I always get different values for student and grade when I try to insert grade for another student and subject in that class, which means parameters val1, val2 are changeable so there are no bugs there.

It’s like it doesn’t filter every time or I am not using find method correctly. Please check if there are errors with template, maybe I am wrong there.

<br> <br> <br> <br> <br>
<center>

<table>

<h2> Chosen class: {{model.name}} </h2>

<br>

<i> Current students in class: </i> <br>

<ol> 
{{#each model.students as |student|}}
  <li> {{student.firstName}}  {{student.lastName}} </li>
    {{#if showS}}
    <br> Current subjects in class: 
    {{#each model.subjects as |subject|}}
      <br> <b> {{subject.title}} </b>
       Choose grade: 
      <select onchange={{action (mut ocena) value="target.value"}}>
        <option value="1"> 1 </option>
        <option value="2"> 2 </option>
        <option value="3"> 3 </option>
        <option value="4"> 4 </option>
        <option value="5"> 5 </option>
      </select>
      <br>
      <button {{action 'unesiOcenu' student.id subject.id}}> Insert mark for student </button>
    {{/each}}

      {{#each student.grades as |grades|}}
			<table>
				<th> {{grades.subject.title}} </th>
				<th> {{grades.marks}} </th>
			</table>
		{{/each}}
  {{/if}}
{{else}}
  <b> Currently there are no students for the class! </b>
{{/each}}
</ol>

</table>
  <button class="choose" {{action 'showSubjects'}}> Show subjects </button> 
</center>

-Also I will leave screenshots of bug I am seeing, I think that then it will be clear what the bug is.

-First insertion of the grade:

-Second insertion of the grade (from different subject):


#7

Nothing is jumping out at me on first glance, but I’ll suggest some things here that may help you debug and I’ll take another look when I get a chance.

First, one way you could clean up your code a tiny bit is to pass the records directly into your action instead of ID’s. This will save you the trouble of using peekRecord to look them back up. Essentially in your template you could change the button to look like this:

<button {{action 'unesiOcenu' student subject}}> Insert mark for student </button>

And then the action would just become:

unesiOcenu(student, subject){
  var mark = this.get('ocena');
			
  alert(student.get('firstName') +  " " +  student.get('lastName'));
  alert(subject.get('title'));
			
  var grades = this.store.peekAll('grade');
  ...

I don’t think that will solve the problem at all, it’s just a way to make the code a little more concise and save some overhead on calling peekRecord.

As far as debugging goes, I would strongly recommend using console.log instead of alert(/*...*/) and better yet, using breakpoints and stepping through the code instead of alerts or console logs. I may be misremembering but I think I’ve seen issues with the values created in an ‘alert’ not being accurate (there are some subtle timing differences maybe?) so console logs are preferable to me, they’re also a little less annoying because you don’t have to close them.

Apologies if you do this already, but debugging via breakpoints is really the best way to go and will allow you to step through each line of code and see what variable values are what and also when and where they are changing. That’s generally the easiest way to debug an issue like there where you are seeing unexpected behavior. You could put a breakpoint at the top of the unesiOcenu action handler and verify with more certainty what is passed in from the template, and then what happens at each step of the function. If you need any tips on debugging with breakpoints let me know, and be sure to mention what browser you’re using (I prefer Chrome personally).


#8

@dknutsen Those are all excellent advises my friend I will definitely check them out. And I will write additional response.

I have two questions for you:

  1. Is there a way I could return grades but if there are no grades available to return directly null? And not not null values? Maybe not using peekAll for grades?
  2. And what type of filtering to you use usually?

#9

for 1. you could write a utility function like this:

findGradesFor(student, subject) {
  var grades = this.store.peekAll('grade');
  // this is just a concise version of the filtering you were doing above, it will filter only grades with matching subject and student
  grades.filter((grade) => {
    return grade.get('student') === student && grade.get('subject') === subject;
  });
  // this just basically says "if there are any filtered grades, return them, otherwise return null"
  return !!grades.get('length') ? grades : null;
}

To use this utility function in your action, simply do this:

unesiOcenu(student, subject){
  var mark = this.get('ocena');
			
  alert(student.get('firstName') +  " " +  student.get('lastName'));
  alert(subject.get('title'));
			
  var filteredGrades = findGradesFor(student, subject);
  // here filteredGrades will either be a RecordArray or it will be (strictly) null
  ...

For 2. it depends on the context. Usually I either use javascript filtering (<array>.filter(/*filter function*/)) or I use Ember.computed.filterBy or just .filterBy. If you wanted to use Ember’s .filterBy you could rewrite the above utility function like this:

findGradesFor(student, subject) {
  var grades = this.store.peekAll('grade');
  // use a chained filterBy to filter first by student, then by subject
  grades.filterBy('student', student).filterBy('subject', subject);
  // this just basically says "if there are any filtered grades, return them, otherwise return null"
  return !!grades.get('length') ? grades : null;
}

#10

I still get the same bug… :smiley: It feels like I am cursed… :smiley: Please, if you can, try to implement this in your small application in new project, you have all the models that I have and template and controller… I used firebase as a backend, I am sure you are familiar with this. Thanks for all great advises so far! :slight_smile:


Stuck with the same bug
#11

Have you tried setting some breakpoints and stepping through with the debugger?


#12

No, I am planning to do that, I am new to the ember.js so I am not skilled with that. But everything else I did try (all the code and console.log instead of alert and so on) I plan to organize code differently, that is to change implementation to easier implementation. If you have any interesting and useful articles about debugger send it to me. and of course if you have time try to implement it. I would be grateful. :slight_smile:


#13

Unfortunately there’s no way I will have time to try and reimplement your app. If you could make a jsfiddle or a stripped down version in a public repo I would be happy to try and take a look at some point but I’d recommend you invest some time in debugging practice anyway.

Debuggers are an invaluable tool in any language, javascript included. Most of the tools and methods you use are very similar to those in the IDE for any language (breakpoints, stepping, etc) so if you take some time to learn good debugging practice it will help you in any language/framework.

I’m sure there are many great debugging articles out there, definitely do some google research, but the basics as they relate to Ember can be described pretty easily. Sorry if you know some of this already just figured it helps to be thorough.

First, open up the developer console. I prefer Chrome and in Chrome it’s called the “Developer Tools” under “More Tools” in the menu. If you’re on a mac you can open it with command + option + i, if you’re on Windows I think it’s usually F12. Safari and Firefox will look pretty similar but things will look a little different and names may be a little different. Anyway, once you have that opened it should look something like this:

This is the javascript console, which allows you to enter javascript commands, look at console.log debug output, etc. And of course see deprecation warnings like you see in the screenshot.

Next, click the “Sources” tab, which will show you all the code your browser has loaded for the app. You’ll want to look under “assets”, then under your project name, then go to “controllers”, then find the name of your controller and click that file. It should open up the controller code in the pane to the right like this:

Find the function you want to debug, probably unesiOcenu in your case, and put a breakpoint on the first line of the function (it won’t allow you to breakpoint a comment or whitespace so it has to be a “logical line”). To place a breakpoint, just click the line number corresponding to that line on the left and it should make a little blue arrow over that line number. It should look like this:

A breakpoint is basically a way of telling the debugger “when you hit this line, pause (or “break”)”. Then you can analyze what is in the declared variables and you can step through the function line by line until you figure out what’s going wrong.

Next you’ll want to trigger the breakpoint that you set. To do that, you just need to trigger the action that you set the breakpoint in by clicking in your app. Once the breakpoint is hit, the app execution will pause and the debugger will look like this:

The “current line” has a blue bar across it, and of course since the app paused at the breakpoint, the “current line” is the line with the breakpoint. This is where the fun part starts. On the right part of the debugger pane you should see some buttons that look like this:

From left to right they are: “continue” which unpauses your app execution, “step over” which is probably the most useful button at least for starters, “step in” and “step out” which are used to dive into function calls and back out of function stacks, and then a couple buttons for removing and disabling breakpoints. The first two buttons are probably the only ones you’ll use for starters: “continue” and “step over”. Essentially if you “step over” a line, you’re just advancing one line in the current function.

So let’s step over a couple lines and see what happens. In my example here I pressed the “step over” button three times, which executed the first three lines of the function.

As you can see the blue bar representing the “current line” is all the way down below the ugly comment (which the debugger ignores). What you also might notice, and which is the cool part, is that I can see what’s in the variables that were defined in the first three lines, for example it actually shows me that “orderStatus” is “Open”. Further, if you hover your mouse over a variable, it will show you the value in a little popover kinda like this:

In this case, ‘self’ is a complex object (it’s the controller itself) and I can see all of the properties and functions defined on that object when I hover over it. It’s very powerful and can let you look at code exactly as it’s running. It definitely beats using alerts or console.logs. What you’ll want to do is, starting with your action, put a breakpoint at the top and then step through the entire function, looking at all the variables and trying to figure out where the bug is occurring. Note that any code in a “then” block is actually another function and it is run asynchronously, so to debug that you’ll also want to put a breakpoint in the “then” block and then hit “continue” to let the app continue running until it hits the “then” block.

Anyway, hope all that can help get you started. I can’t emphasize enough how important good debugging practice is (and again that applies to any programming language and framework). It will help you tremendously in being able to debug issues like the one you’re seeing and it takes a lot of the guesswork out.


#14

@dknutsen thank you very much for all these advises for debugging I will definitely use them in the near future.

By the way, I have some nice news, here is the screenshot of the new realization of my application. I have now used all CRUD operations with data base. So I am proud of that. :slight_smile: Here is the screenshot, I am sure you will know what is being done even though its all in Serbian, but I wrote a comment near functions in red letters. :slight_smile:

I also have two questions:

  1. Is there a way where I can use a button for showing/hiding content separately for every item in each loop? Because I only know how to toggle single property.

  2. Is there a way where I can slowly show content not immediately?

And here is the screenshot of my “upgraded” application. :slight_smile: